Changeset 3422687
- Timestamp:
- 12/18/2025 09:39:57 AM (3 months ago)
- Location:
- mass-email-notifications-for-gravity-forms
- Files:
-
- 2 added
- 36 edited
- 1 copied
-
tags/1.3.6 (copied) (copied from mass-email-notifications-for-gravity-forms/trunk)
-
tags/1.3.6/class-mass-email-notifications-for-gravity-forms.php (modified) (5 diffs)
-
tags/1.3.6/mass-email-notifications-for-gf.php (modified) (4 diffs)
-
tags/1.3.6/readme.txt (modified) (3 diffs)
-
tags/1.3.6/vendor/MENFGF/autoload.php (modified) (1 diff)
-
tags/1.3.6/vendor/MENFGF/composer/autoload_real.php (modified) (2 diffs)
-
tags/1.3.6/vendor/MENFGF/composer/autoload_static.php (modified) (2 diffs)
-
tags/1.3.6/vendor/MENFGF/composer/installed.json (modified) (2 diffs)
-
tags/1.3.6/vendor/MENFGF/composer/installed.php (modified) (2 diffs)
-
tags/1.3.6/vendor/MENFGF/gravityops/core/src/Admin/AdminShell.php (modified) (17 diffs)
-
tags/1.3.6/vendor/MENFGF/gravityops/core/src/Admin/SuiteMenu.php (modified) (12 diffs)
-
tags/1.3.6/vendor/MENFGF/gravityops/core/src/Admin/functions.php (added)
-
tags/1.3.6/vendor/MENFGF/gravityops/core/src/SuiteRegistry.php (modified) (6 diffs)
-
tags/1.3.6/vendor/autoload.php (modified) (1 diff)
-
tags/1.3.6/vendor/composer/autoload_aliases.php (modified) (1 diff)
-
tags/1.3.6/vendor/composer/autoload_files.php (modified) (1 diff)
-
tags/1.3.6/vendor/composer/autoload_real.php (modified) (2 diffs)
-
tags/1.3.6/vendor/composer/autoload_static.php (modified) (2 diffs)
-
tags/1.3.6/vendor/composer/installed.json (modified) (2 diffs)
-
tags/1.3.6/vendor/composer/installed.php (modified) (3 diffs)
-
trunk/class-mass-email-notifications-for-gravity-forms.php (modified) (5 diffs)
-
trunk/mass-email-notifications-for-gf.php (modified) (4 diffs)
-
trunk/readme.txt (modified) (3 diffs)
-
trunk/vendor/MENFGF/autoload.php (modified) (1 diff)
-
trunk/vendor/MENFGF/composer/autoload_real.php (modified) (2 diffs)
-
trunk/vendor/MENFGF/composer/autoload_static.php (modified) (2 diffs)
-
trunk/vendor/MENFGF/composer/installed.json (modified) (2 diffs)
-
trunk/vendor/MENFGF/composer/installed.php (modified) (2 diffs)
-
trunk/vendor/MENFGF/gravityops/core/src/Admin/AdminShell.php (modified) (17 diffs)
-
trunk/vendor/MENFGF/gravityops/core/src/Admin/SuiteMenu.php (modified) (12 diffs)
-
trunk/vendor/MENFGF/gravityops/core/src/Admin/functions.php (added)
-
trunk/vendor/MENFGF/gravityops/core/src/SuiteRegistry.php (modified) (6 diffs)
-
trunk/vendor/autoload.php (modified) (1 diff)
-
trunk/vendor/composer/autoload_aliases.php (modified) (1 diff)
-
trunk/vendor/composer/autoload_files.php (modified) (1 diff)
-
trunk/vendor/composer/autoload_real.php (modified) (2 diffs)
-
trunk/vendor/composer/autoload_static.php (modified) (2 diffs)
-
trunk/vendor/composer/installed.json (modified) (2 diffs)
-
trunk/vendor/composer/installed.php (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
mass-email-notifications-for-gravity-forms/tags/1.3.6/class-mass-email-notifications-for-gravity-forms.php
r3420209 r3422687 8 8 use MENFGF\GravityOps\Core\Utils\AssetHelper; 9 9 use MENFGF\GravityOps\Core\Admin\AdminShell; 10 use function MENFGF\GravityOps\Core\Admin\gravityops_shell; 10 11 if ( !defined( 'ABSPATH' ) ) { 11 12 exit; … … 206 207 parent::init_admin(); 207 208 // Register the new GravityOps AdminShell page under the parent menu. 208 AdminShell::instance()->register_plugin_page( $this->_slug, [209 gravityops_shell()->register_plugin_page( $this->_slug, [ 209 210 'title' => $this->_title, 210 211 'menu_title' => $this->_short_title, … … 326 327 */ 327 328 public function gops_render_suppressions() { 329 $groups = $this->get_structured_suppressions(); 328 330 echo '<div class="gops-card">'; 329 echo '<h2 class="gops-title" style="margin:0 0 8px;">Suppressions</h2>'; 330 if ( !method_exists( $this, 'get_structured_suppressions' ) ) { 331 echo '<p>Suppression list is not available.</p>'; 332 echo '</div>'; 333 return; 334 } 335 $groups = $this->get_structured_suppressions(); 336 if ( empty( $groups ) || !is_array( $groups ) ) { 331 echo '<h2 class="gops-title" style="margin:0 0 8px;">Suppressions (' . count( $groups ) . ')</h2>'; 332 if ( empty( $groups ) ) { 337 333 echo '<p>No suppressed emails found.</p>'; 338 334 echo '</div>'; … … 2267 2263 header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) ); 2268 2264 echo '<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">' . '<title>Unsubscribed</title>' . '<style>body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;line-height:1.5;padding:40px;background:#f6f7f9;color:#1d2327} .menfgf-unsub{max-width:560px;margin:40px auto;background:#fff;border:1px solid #ccd0d4;border-radius:8px;padding:24px;box-shadow:0 3px 8px rgba(0,0,0,.05)} .menfgf-unsub h1{font-size:20px;margin:0 0 8px} .menfgf-unsub p{margin:8px 0 0;color:#3c434a}</style></head><body>' . '<div class="menfgf-unsub"><h1>You have been unsubscribed</h1><p>You will no longer receive these mass email notifications from this site. You can close this tab.</p></div>' . '</body></html>'; 2269 wp_die();2265 exit; 2270 2266 } 2271 2267 … … 2960 2956 false, 2961 2957 false, 2962 $disable_auto_format2958 !$disable_auto_format 2963 2959 ); 2964 2960 $this->log_debug( __METHOD__ . '() - processed text ' . $processed_text ); -
mass-email-notifications-for-gravity-forms/tags/1.3.6/mass-email-notifications-for-gf.php
r3420881 r3422687 6 6 * Author URI: https://brightleafdigital.io/ 7 7 * Description: Allows you to send notifications to everyone who filled out any of your forms. 8 * Version: 1.3. 58 * Version: 1.3.6 9 9 * Author: BrightLeaf Digital 10 10 * License: GPL-2.0+ … … 13 13 * @package MassEmailNotificationsForGravityForms 14 14 */ 15 use MENFGF\GravityOps\Core\Admin\AdminShell; 15 16 if ( !defined( 'ABSPATH' ) ) { 16 17 exit; … … 18 19 } 19 20 require_once __DIR__ . '/vendor/autoload.php'; 21 // Instantiate this plugin's copy of the AdminShell early so provider negotiation can happen on plugins_loaded. 22 add_action( 'plugins_loaded', function () { 23 AdminShell::instance(); 24 }, 1 ); 20 25 if ( function_exists( 'menfgf_fs' ) ) { 21 26 menfgf_fs()->set_basename( false, __FILE__ ); … … 66 71 } 67 72 menfgf_fs()->add_filter( 'enable_cpt_advanced_menu_logic', '__return_true' ); 68 define( 'MASS_EMAIL_NOTIFICATIONS_FOR_GRAVITY_FORMS_VERSION', '1.3. 5' );73 define( 'MASS_EMAIL_NOTIFICATIONS_FOR_GRAVITY_FORMS_VERSION', '1.3.6' ); 69 74 define( 'MASS_EMAIL_NOTIFICATIONS_FOR_GRAVITY_FORMS_BASENAME', plugin_basename( __FILE__ ) ); 70 75 add_action( 'admin_notices', function () { -
mass-email-notifications-for-gravity-forms/tags/1.3.6/readme.txt
r3420881 r3422687 2 2 Tested up to: 6.9 3 3 Tags: GravityForms, notifications, email, task management, automation 4 Stable tag: 1.3. 54 Stable tag: 1.3.6 5 5 Requires PHP: 8.0 6 6 License: GPLv2 or later … … 44 44 == Changelog == 45 45 46 = 1.3.6 | Dec 18, 2025 = 47 * Fixed a bug in the new plugin menu where installed plugins would show as uninstalled 48 * Fixed some PHP error warnings 49 * Fixed a 500 response error returned when someone unsubscribed without a landing page configured 50 * Fixed a bug preventing auto formatting being disabled in some circumstances 51 46 52 = 1.3.5 | Dec 16, 2025 = 47 53 * Fixed another bug in new plugin menu … … 62 68 * Added shortocde support for premium and agency plans. 63 69 * Added a GravityFlow workflow step for premium and agency plans. 64 65 = 1.3.1 =66 * A few small quality of life improvements.67 68 = 1.3.0 =69 * A host of small UI/UX enhancements.70 * Added unsubscribe management features.71 * Added double opt-in management features.72 73 = 1.2.9 =74 * Fixed a bug where feed labels would not always display in the batch table. -
mass-email-notifications-for-gravity-forms/tags/1.3.6/vendor/MENFGF/autoload.php
r3420881 r3422687 20 20 require_once __DIR__ . '/composer/autoload_real.php'; 21 21 22 return ComposerAutoloaderInit 0fa87d9e4ab62c721e5fc11d03c1d808::getLoader();22 return ComposerAutoloaderInitf3a8ee65c4639a42d5f2af71ff334aaa::getLoader(); -
mass-email-notifications-for-gravity-forms/tags/1.3.6/vendor/MENFGF/composer/autoload_real.php
r3420881 r3422687 3 3 // autoload_real.php @generated by Composer 4 4 5 class ComposerAutoloaderInit 0fa87d9e4ab62c721e5fc11d03c1d8085 class ComposerAutoloaderInitf3a8ee65c4639a42d5f2af71ff334aaa 6 6 { 7 7 private static $loader; … … 25 25 require __DIR__ . '/platform_check.php'; 26 26 27 spl_autoload_register(array('ComposerAutoloaderInit 0fa87d9e4ab62c721e5fc11d03c1d808', 'loadClassLoader'), true, true);27 spl_autoload_register(array('ComposerAutoloaderInitf3a8ee65c4639a42d5f2af71ff334aaa', 'loadClassLoader'), true, true); 28 28 self::$loader = $loader = new \MENFGF\Composer\Autoload\ClassLoader(\dirname(__DIR__)); 29 spl_autoload_unregister(array('ComposerAutoloaderInit 0fa87d9e4ab62c721e5fc11d03c1d808', 'loadClassLoader'));29 spl_autoload_unregister(array('ComposerAutoloaderInitf3a8ee65c4639a42d5f2af71ff334aaa', 'loadClassLoader')); 30 30 31 31 require __DIR__ . '/autoload_static.php'; 32 call_user_func(\MENFGF\Composer\Autoload\ComposerStaticInit 0fa87d9e4ab62c721e5fc11d03c1d808::getInitializer($loader));32 call_user_func(\MENFGF\Composer\Autoload\ComposerStaticInitf3a8ee65c4639a42d5f2af71ff334aaa::getInitializer($loader)); 33 33 34 34 $loader->setClassMapAuthoritative(true); -
mass-email-notifications-for-gravity-forms/tags/1.3.6/vendor/MENFGF/composer/autoload_static.php
r3420881 r3422687 5 5 namespace MENFGF\Composer\Autoload; 6 6 7 class ComposerStaticInit 0fa87d9e4ab62c721e5fc11d03c1d8087 class ComposerStaticInitf3a8ee65c4639a42d5f2af71ff334aaa 8 8 { 9 9 public static $prefixLengthsPsr4 = array ( … … 36 36 { 37 37 return \Closure::bind(function () use ($loader) { 38 $loader->prefixLengthsPsr4 = ComposerStaticInit 0fa87d9e4ab62c721e5fc11d03c1d808::$prefixLengthsPsr4;39 $loader->prefixDirsPsr4 = ComposerStaticInit 0fa87d9e4ab62c721e5fc11d03c1d808::$prefixDirsPsr4;40 $loader->classMap = ComposerStaticInit 0fa87d9e4ab62c721e5fc11d03c1d808::$classMap;38 $loader->prefixLengthsPsr4 = ComposerStaticInitf3a8ee65c4639a42d5f2af71ff334aaa::$prefixLengthsPsr4; 39 $loader->prefixDirsPsr4 = ComposerStaticInitf3a8ee65c4639a42d5f2af71ff334aaa::$prefixDirsPsr4; 40 $loader->classMap = ComposerStaticInitf3a8ee65c4639a42d5f2af71ff334aaa::$classMap; 41 41 42 42 }, null, ClassLoader::class); -
mass-email-notifications-for-gravity-forms/tags/1.3.6/vendor/MENFGF/composer/installed.json
r3420881 r3422687 3 3 "1": { 4 4 "name": "gravityops/core", 5 "version": "1.0. 18",6 "version_normalized": "1.0. 18.0",5 "version": "1.0.21", 6 "version_normalized": "1.0.21.0", 7 7 "source": { 8 8 "type": "git", 9 9 "url": "git@github.com:Eitan-brightleaf/gravityops.git", 10 "reference": " a74352489b658ed6a7f1c588abb2e18aae065a68"10 "reference": "5d859a7cca5cf8c1e469c80a88e755fb1be7c522" 11 11 }, 12 12 "dist": { 13 13 "type": "zip", 14 "url": "https://api.github.com/repos/Eitan-brightleaf/gravityops/zipball/ a74352489b658ed6a7f1c588abb2e18aae065a68",15 "reference": " a74352489b658ed6a7f1c588abb2e18aae065a68",14 "url": "https://api.github.com/repos/Eitan-brightleaf/gravityops/zipball/5d859a7cca5cf8c1e469c80a88e755fb1be7c522", 15 "reference": "5d859a7cca5cf8c1e469c80a88e755fb1be7c522", 16 16 "shasum": "" 17 17 }, … … 19 19 "php": ">=7.4" 20 20 }, 21 "time": "2025-12-1 6T09:58:09+00:00",21 "time": "2025-12-18T07:45:02+00:00", 22 22 "type": "library", 23 23 "installation-source": "source", -
mass-email-notifications-for-gravity-forms/tags/1.3.6/vendor/MENFGF/composer/installed.php
r3420881 r3422687 5 5 'pretty_version' => 'dev-main', 6 6 'version' => 'dev-main', 7 'reference' => ' f0ab76d4401e26cd5563866f07e0110432efba26',7 'reference' => '4b921b3009464563093dfd512b32f402b1533e6b', 8 8 'type' => 'library', 9 9 'install_path' => __DIR__ . '/../', … … 17 17 'gravityops/core' => 18 18 array ( 19 'pretty_version' => '1.0. 18',20 'version' => '1.0. 18.0',21 'reference' => ' a74352489b658ed6a7f1c588abb2e18aae065a68',19 'pretty_version' => '1.0.21', 20 'version' => '1.0.21.0', 21 'reference' => '5d859a7cca5cf8c1e469c80a88e755fb1be7c522', 22 22 'type' => 'library', 23 23 'install_path' => __DIR__ . '/../gravityops/core', -
mass-email-notifications-for-gravity-forms/tags/1.3.6/vendor/MENFGF/gravityops/core/src/Admin/AdminShell.php
r3420881 r3422687 16 16 17 17 /** 18 * Library/core version used for provider negotiation. 19 * The highest version across loaded copies should be selected as provider. 20 */ 21 public const CORE_VERSION = '1.0.21'; 22 23 /** 18 24 * Holds the singleton instance. 19 25 * … … 21 27 */ 22 28 private static ?AdminShell $instance = null; 29 30 /** 31 * Tracks whether the chosen provider has already booted (registered hooks). 32 * Prevents multiple copies from attaching side‑effect hooks. 33 * 34 * @var bool 35 */ 36 private static bool $did_boot = false; 23 37 24 38 /** … … 35 49 * Get singleton instance. 36 50 */ 37 public static function instance(): AdminShell { 38 // First, try to get a shared instance provided by any loaded copy via filter. 51 public static function instance() { 52 // New: negotiate best provider by highest version (cross‑namespace). 53 $best = apply_filters( 'gravityops_shell_provider', null ); 54 if ( is_array( $best ) && isset( $best['shell'] ) ) { 55 return $best['shell']; 56 } 57 58 // Legacy: try a shared instance provided by any copy. 39 59 $shared = apply_filters( 'gravityops_shell_instance', null ); 40 60 if ( $shared instanceof self ) { 41 61 return $shared; 42 62 } 63 43 64 if ( null === self::$instance ) { 44 65 self::$instance = new self(); … … 53 74 */ 54 75 private function __construct() { 55 // Cross-namespace shared instance resolver: first provider wins. 56 $existing = apply_filters( 'gravityops_shell_instance', null ); 57 if ( $existing && $existing !== $this ) { 58 // Another copy has already provided an instance; avoid duplicate hooks. 59 return; 60 } 61 62 // Expose this instance for other namespaces/copies to reuse. 76 // Expose this instance for other namespaces/copies to reuse (legacy "first copy wins"). 63 77 add_filter( 64 78 'gravityops_shell_instance', … … 69 83 ); 70 84 71 // Defer adding menus until after all plugins have registered. 72 add_action( 'admin_menu', [ $this, 'register_menus' ], 99 ); 73 // Do NOT hide submenus by default; users reported accessibility issues. 74 // If needed in the future, this can be reintroduced behind a filter. 75 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] ); 85 // Versioned provider negotiation: highest version wins. 86 add_filter( 87 'gravityops_shell_provider', 88 function ( $best ) { 89 $mine = [ 90 'version' => self::CORE_VERSION, 91 'shell' => $this, 92 ]; 93 if ( ! is_array( $best ) || empty( $best['version'] ) ) { 94 return $mine; 95 } 96 return version_compare( (string) $mine['version'], (string) $best['version'], '>' ) ? $mine : $best; 97 }, 98 1 99 ); 100 101 // Defer side‑effect hooks until we negotiate the best provider. 102 // Each copy registers this, but only the selected provider will actually boot. 103 // If instantiated after plugins_loaded has already fired, boot immediately. 104 if ( function_exists( 'did_action' ) && did_action( 'plugins_loaded' ) ) { 105 $this->maybe_boot(); 106 } else { 107 add_action( 'plugins_loaded', [ $this, 'maybe_boot' ], 20 ); 108 } 76 109 } 77 110 … … 84 117 * @return bool True if the page exists. 85 118 */ 86 public static function has_page( string $slug ): bool{119 public static function has_page( $slug ) { 87 120 $provider = apply_filters( 'gravityops_shell_instance', null ); 88 121 if ( $provider instanceof self ) { … … 112 145 * @return array<string,array<string,string>> Tabs config array suitable to merge with register_plugin_page() tabs. 113 146 */ 114 public static function freemius_tabs( string $plugin_slug, array $labels = [] ): array{147 public static function freemius_tabs( $plugin_slug, $labels = [] ) { 115 148 $default_labels = [ 116 149 'account' => 'Account', … … 164 197 * @return void 165 198 */ 166 public static function render_feeds_list( array $feeds_and_forms, string $gf_subview_slug, string $plugin_short_title, string $toggle_action ): void{199 public static function render_feeds_list( $feeds_and_forms, $gf_subview_slug, $plugin_short_title, $toggle_action ) { 167 200 echo '<div class="gops-card">'; 168 201 echo '<h2 class="gops-title" style="margin:0 0 10px;">' . esc_html( $plugin_short_title ) . ' Feeds</h2>'; … … 224 257 * @return void 225 258 */ 226 public static function process_feed_toggle( string $action_prefix, string$return_url ) {259 public static function process_feed_toggle( $action_prefix, $return_url ) { 227 260 if ( empty( wp_unslash( $_SERVER['REQUEST_METHOD'] ) ) || 'POST' !== ( wp_unslash( $_SERVER['REQUEST_METHOD'] ) ?? '' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized 228 261 wp_safe_redirect( admin_url( $return_url ) ); … … 262 295 * @return void 263 296 */ 264 public static function render_help_tab( array $links ): void{297 public static function render_help_tab( $links ) { 265 298 echo '<div class="gops-card">'; 266 299 echo '<h2 class="gops-title" style="margin:0 0 8px;">Help</h2>'; … … 282 315 * @param array $args Page configuration. 283 316 */ 284 public function register_plugin_page( string $slug, array $args ): void { 285 // If another copy is the active provider, forward registration to it. 317 public function register_plugin_page( $slug, $args ) { 318 // If another copy is the active provider (new negotiation), forward registration to it first. 319 $best = apply_filters( 'gravityops_shell_provider', null ); 320 if ( is_array( $best ) && isset( $best['shell'] ) && $best['shell'] !== $this && is_object( $best['shell'] ) && method_exists( $best['shell'], 'register_plugin_page' ) ) { 321 $best['shell']->register_plugin_page( $slug, $args ); 322 return; 323 } 324 // Legacy shared-instance forwarding as a fallback. 286 325 $provider = apply_filters( 'gravityops_shell_instance', null ); 287 326 if ( $provider && $provider !== $this && is_object( $provider ) && method_exists( $provider, 'register_plugin_page' ) ) { 288 // Call method on the provider (may be a different class/namespace).289 327 $provider->register_plugin_page( $slug, $args ); 290 328 return; … … 304 342 * Add the submenu pages under the shared GravityOps parent. 305 343 */ 306 public function register_menus() : void{344 public function register_menus() { 307 345 if ( class_exists( __NAMESPACE__ . '\\SuiteMenu' ) ) { 308 346 SuiteMenu::ensure_parent_menu(); … … 342 380 * @param string $hook Current admin page hook. 343 381 */ 344 public function enqueue_assets( $hook ) : void{382 public function enqueue_assets( $hook ) { 345 383 $page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended 346 384 … … 375 413 376 414 /** 415 * Boot the chosen provider (register side‑effect hooks). Called once. 416 * 417 * @return void 418 */ 419 private function boot() { 420 if ( self::$did_boot ) { 421 return; 422 } 423 // Defer adding menus until after all plugins have registered. 424 add_action( 'admin_menu', [ $this, 'register_menus' ], 99 ); 425 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] ); 426 self::$did_boot = true; 427 } 428 429 /** 430 * On plugins_loaded, negotiate the best provider and boot only that one. 431 * Each copy registers this callback, but only the selected provider acts. 432 * 433 * @return void 434 */ 435 public function maybe_boot() { 436 if ( self::$did_boot ) { 437 return; 438 } 439 $best = apply_filters( 'gravityops_shell_provider', null ); 440 if ( is_array( $best ) && isset( $best['shell'] ) ) { 441 if ( $best['shell'] === $this ) { 442 $this->boot(); 443 } 444 return; 445 } 446 // If no provider negotiation is available, fall back to local boot (legacy environments). 447 $shared = apply_filters( 'gravityops_shell_instance', null ); 448 if ( $shared && $shared !== $this ) { 449 // Another copy is acting as shared instance; let it boot on its own call. 450 return; 451 } 452 $this->boot(); 453 } 454 455 /** 377 456 * Render the complete page including header, pills, and tab content. 378 457 * … … 380 459 * @param array $args Page config. 381 460 */ 382 public function render_page( string $slug, array $args ): void{461 public function render_page( $slug, $args ) { 383 462 if ( ! current_user_can( $args['capability'] ?? 'manage_options' ) ) { 384 463 return; … … 435 514 * @return void 436 515 */ 437 private function render_header_only( array $args ): void{516 private function render_header_only( $args ) { 438 517 ?> 439 518 <header class="gops-header"> … … 471 550 * @return array{css:string,js:string} 472 551 */ 473 public static function resolve_assets_urls() : array{552 public static function resolve_assets_urls() { 474 553 $base_url = apply_filters( 'gravityops_assets_base_url', '' ); 475 554 $css = ''; -
mass-email-notifications-for-gravity-forms/tags/1.3.6/vendor/MENFGF/gravityops/core/src/Admin/SuiteMenu.php
r3420881 r3422687 30 30 */ 31 31 private static $did_notice_hook = false; 32 33 /** 34 * Track whether the parent GravityOps menu has already been registered. 35 * Prevents duplicate add_menu_page() calls and ensures a single owner of the parent page. 36 * 37 * @var bool 38 */ 39 private static $did_parent_menu = false; 32 40 33 41 /** … … 55 63 */ 56 64 public static function ensure_parent_menu( $capability = '' ) { 57 global $menu; 58 59 $menu_slug = 'gravity_ops'; 60 61 // If another plugin in the suite has already created the menu, we don't need to do anything. 62 if ( ! empty( $menu ) && in_array( $menu_slug, array_column( $menu, 2 ), true ) ) { 63 return; 65 global $menu; 66 67 $menu_slug = 'gravity_ops'; 68 69 // Internal idempotency guard — if we've already added the parent once this request, bail. 70 if ( self::$did_parent_menu ) { 71 return; 72 } 73 74 // If another plugin in the suite has already created the menu, we don't need to do anything. 75 if ( ! empty( $menu ) && in_array( $menu_slug, array_column( $menu, 2 ), true ) ) { 76 return; 64 77 } 65 78 … … 128 141 if ( $hook ) { 129 142 add_action( 'load-' . $hook, [ self::class, 'maybe_handle_plugin_toggle' ] ); 130 } 143 } 144 145 // Mark parent as registered to avoid duplicate add_menu_page calls in mixed environments. 146 self::$did_parent_menu = true; 131 147 132 148 // Ensure assets are enqueued at the proper time and only on our screen. … … 134 150 add_action( 'admin_enqueue_scripts', [ self::class, 'enqueue_assets' ] ); 135 151 self::$did_enqueue_hook = true; 136 }152 } 137 153 138 154 // Register admin notices renderer (error/success messages from actions below). … … 140 156 add_action( 'admin_notices', [ self::class, 'render_admin_notices' ] ); 141 157 self::$did_notice_hook = true; 142 }158 } 143 159 } 144 160 … … 173 189 $updates_count = 0; 174 190 175 // Annotate registry items with runtime state .191 // Annotate registry items with runtime state (supports premium/free variant pairs). 176 192 foreach ( $registry as $key => $item ) { 177 193 $type = $item['type'] ?? 'plugin'; … … 179 195 continue; 180 196 } 181 182 $file = $item['plugin_file']; 183 $is_installed = isset( $installed_plugins[ $file ] ); 184 $is_active = $is_installed && is_plugin_active( $file ); 185 $version = $is_installed ? ( $installed_plugins[ $file ]['Version'] ?? '' ) : ''; 186 187 $has_update = isset( $update_response[ $file ] ); 188 if ( $has_update ) { 197 $primary_file = (string) $item['plugin_file']; 198 $premium_file = isset( $item['plugin_files']['premium'] ) ? (string) $item['plugin_files']['premium'] : ''; 199 $free_file = isset( $item['plugin_files']['free'] ) ? (string) $item['plugin_files']['free'] : ''; 200 201 // Helper to read state for a specific plugin file 202 $read_state = function ( string $file ) use ( $installed_plugins, $update_response ) { 203 $installed = isset( $installed_plugins[ $file ] ); 204 $active = $installed && is_plugin_active( $file ); 205 $version = $installed ? ( $installed_plugins[ $file ]['Version'] ?? '' ) : ''; 206 $has_upd = isset( $update_response[ $file ] ); 207 $new_ver = $has_upd ? ( $update_response[ $file ]->new_version ?? '' ) : ''; 208 return [ $installed, $active, $version, $has_upd, $new_ver ]; 209 }; 210 211 // Default path: single-file plugins 212 if ( empty( $premium_file ) && empty( $free_file ) ) { 213 [ $is_installed, $is_active, $version, $has_update, $new_version ] = $read_state( $primary_file ); 214 if ( $has_update ) { 215 ++$updates_count; 216 } 217 $registry[ $key ]['is_installed'] = $is_installed; 218 $registry[ $key ]['is_active'] = $is_active; 219 $registry[ $key ]['version'] = $version; 220 $registry[ $key ]['has_update'] = $has_update; 221 $registry[ $key ]['new_version'] = $new_version; 222 $registry[ $key ]['plugin_file_active'] = $is_active ? $primary_file : ''; 223 $registry[ $key ]['plugin_file_action'] = $primary_file; 224 $registry[ $key ]['uses_free'] = false; 225 continue; 226 } 227 228 // Variant-aware path: prefer premium when present 229 $is_installed_prem = false; 230 $is_active_prem = false; 231 $ver_prem = ''; 232 $upd_prem = false; 233 $new_prem = ''; 234 $is_installed_free = false; 235 $is_active_free = false; 236 $ver_free = ''; 237 $upd_free = false; 238 $new_free = ''; 239 240 if ( $premium_file ) { 241 [ $is_installed_prem, $is_active_prem, $ver_prem, $upd_prem, $new_prem ] = $read_state( $premium_file ); 242 } 243 if ( $free_file ) { 244 [ $is_installed_free, $is_active_free, $ver_free, $upd_free, $new_free ] = $read_state( $free_file ); 245 } 246 247 $is_installed = $is_installed_prem || $is_installed_free; 248 $is_active = $is_active_prem || $is_active_free; 249 $uses_free = false; 250 $version = ''; 251 $file_active = ''; 252 $has_update = false; 253 $new_version = ''; 254 255 // Choose versions and update flags based on precedence 256 if ( $is_active_prem ) { 257 $file_active = $premium_file; 258 $version = $ver_prem; 259 } elseif ( $is_active_free ) { 260 $file_active = $free_file; 261 $version = $ver_free; 262 $uses_free = true; 263 } elseif ( $is_installed_prem ) { 264 $version = $ver_prem; 265 } elseif ( $is_installed_free ) { 266 $version = $ver_free; 267 $uses_free = true; // Only free exists → show Free badge 268 } 269 270 // Updates: consider whichever is installed; prefer premium if both 271 if ( $upd_prem || $upd_free ) { 272 $has_update = $upd_prem || $upd_free; 273 $new_version = $upd_prem ? $new_prem : $new_free; 189 274 ++$updates_count; 190 275 } 191 276 192 $registry[ $key ]['is_installed'] = $is_installed; 193 $registry[ $key ]['is_active'] = $is_active; 194 $registry[ $key ]['version'] = $version; 195 $registry[ $key ]['has_update'] = $has_update; 196 $registry[ $key ]['new_version'] = $has_update ? ( $update_response[ $file ]->new_version ?? '' ) : ''; 277 // Activation target: if active → target the active file for deactivation. 278 // If inactive → prefer premium when installed; else free. 279 if ( $is_active ) { 280 $file_action = $file_active ?: ( $is_installed_prem ? $premium_file : $free_file ); 281 } else { 282 $file_action = $is_installed_prem ? $premium_file : ( $free_file ?: $premium_file ); 283 } 284 285 $registry[ $key ]['is_installed'] = $is_installed; 286 $registry[ $key ]['is_active'] = $is_active; 287 $registry[ $key ]['version'] = $version; 288 $registry[ $key ]['has_update'] = $has_update; 289 $registry[ $key ]['new_version'] = $new_version; 290 $registry[ $key ]['plugin_file_active'] = $file_active; 291 $registry[ $key ]['plugin_file_action'] = $file_action ?: $primary_file; 292 $registry[ $key ]['uses_free'] = $uses_free; 197 293 } 198 294 … … 319 415 <?php echo $is_active ? 'Active' : ( $is_installed ? 'Inactive' : 'Not Installed' ); ?> 320 416 </span> 417 <?php if ( ! empty( $item['uses_free'] ) ) : ?> 418 <span class="gops-badge">Free</span> 419 <?php endif; ?> 321 420 <?php if ( $version ) : ?> 322 421 <span class="gops-tile__version">v<?php echo esc_html( $version ); ?></span> … … 331 430 <?php if ( current_user_can( 'activate_plugins' ) ) : ?> 332 431 <form class="gops-action" method="post" action="<?php echo esc_url( $base_url ); ?>"> 333 <?php wp_nonce_field( 'gops_toggle_' . $item['plugin_file'], 'gops_nonce' ); ?>432 <?php wp_nonce_field( 'gops_toggle_' . ( $item['plugin_file_action'] ?? $item['plugin_file'] ), 'gops_nonce' ); ?> 334 433 <input type="hidden" name="gops-action" value="<?php echo $is_active ? 'deactivate' : 'activate'; ?>" /> 335 <input type="hidden" name="plugin" value="<?php echo esc_attr( $i tem['plugin_file']); ?>" />434 <input type="hidden" name="plugin" value="<?php echo esc_attr( $is_active ? ( $item['plugin_file_active'] ?: ( $item['plugin_file_action'] ?? $item['plugin_file'] ) ) : ( $item['plugin_file_action'] ?? $item['plugin_file'] ) ); ?>" /> 336 435 <button class="button<?php echo $is_active ? '' : ' button-primary'; ?>" type="submit"><?php echo $is_active ? 'Deactivate' : 'Activate'; ?></button> 337 436 </form> … … 358 457 * @return string Icon URL or empty string if none found. 359 458 */ 360 private static function resolve_plugin_icon_url( array $item ): string{459 private static function resolve_plugin_icon_url( $item ) { 361 460 $url = apply_filters( 'gravityops_plugin_icon_url', '', $item ); 362 461 if ( ! empty( $url ) ) { … … 422 521 * @return void 423 522 */ 424 public static function enqueue_assets( $hook ) : void{523 public static function enqueue_assets( $hook ) { 425 524 $page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended 426 525 $is_gravityops_screen = ( false !== strpos( (string) $hook, 'gravity_ops' ) ) || ( 'gravity_ops' === $page ); … … 452 551 * @return void 453 552 */ 454 public static function render_admin_notices() : void{553 public static function render_admin_notices() { 455 554 $is_gravityops_screen = isset( $_GET['page'] ) && 'gravity_ops' === sanitize_key( wp_unslash( $_GET['page'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended 456 555 if ( ! $is_gravityops_screen ) { -
mass-email-notifications-for-gravity-forms/tags/1.3.6/vendor/MENFGF/gravityops/core/src/SuiteRegistry.php
r3420036 r3422687 25 25 * 'description', 'marketing_url', 'docs_url', 'is_free', and 'icon_html'. 26 26 */ 27 public static function all() : array{27 public static function all() { 28 28 // NOTE: External links are placeholders. Replace with final URLs where marked. 29 29 return [ … … 54 54 'slug' => 'integrate-asana-with-gravity-forms', 55 55 'plugin_file' => 'integrate-asana-with-gravity-forms/integrate-asana-with-gravity-forms.php', 56 // Free + Premium variants: prefer premium folder when present 57 'plugin_files' => [ 58 'premium' => 'integrate-asana-with-gravity-forms-premium/integrate-asana-with-gravity-forms.php', 59 'free' => 'integrate-asana-with-gravity-forms/integrate-asana-with-gravity-forms.php', 60 ], 56 61 'name' => 'Integrate Asana with Gravity Forms', 57 62 'description' => 'Turn form submissions into Asana tasks instantly.', … … 65 70 'slug' => 'mass_email_notifications_for_gf', 66 71 'plugin_file' => 'mass-email-notifications-for-gravity-forms/mass-email-notifications-for-gf.php', 72 // Free + Premium variants: prefer premium folder when present 73 'plugin_files' => [ 74 'premium' => 'mass-email-notifications-for-gravity-forms-premium/mass-email-notifications-for-gf.php', 75 'free' => 'mass-email-notifications-for-gravity-forms/mass-email-notifications-for-gf.php', 76 ], 67 77 'name' => 'Mass Email Notifications', 68 78 'description' => 'Send bulk emails to Gravity Forms entries.', … … 75 85 'type' => 'plugin', 76 86 'slug' => 'kanban-view-for-gravity-view', 77 'plugin_file' => 'kanban-view-for-gravity-view /kanban-view-for-gv.php',87 'plugin_file' => 'kanban-view-for-gravity-view-premium/kanban-view-for-gv.php', 78 88 'name' => 'Kanban View for GravityView', 79 89 'description' => 'Turn GravityView into a kanban project board.', … … 86 96 'type' => 'plugin', 87 97 'slug' => 'Recurring_Form_Submissions_For_Gravity_Form', 88 'plugin_file' => 'recurring-form-submissions-for-gravity-forms /recurring-form-submissions-for-gravity-form.php',98 'plugin_file' => 'recurring-form-submissions-for-gravity-forms-premium/recurring-form-submissions-for-gravity-form.php', 89 99 'name' => 'Recurring Form Submissions', 90 100 'description' => 'Schedule recurring Gravity Forms submissions.', … … 97 107 'type' => 'plugin', 98 108 'slug' => 'gravity_ops_global_variables', 99 'plugin_file' => 'global-variables-for-gravity-math/global-variables-for-gravity-math.php', 109 // Premium-only plugin uses a -premium folder suffix 110 'plugin_file' => 'global-variables-for-gravity-math-premium/global-variables-for-gravity-math.php', 100 111 'name' => 'Global Variables', 101 112 'description' => 'Create shared variables for GravityMath formulas.', -
mass-email-notifications-for-gravity-forms/tags/1.3.6/vendor/autoload.php
r3420881 r3422687 20 20 require_once __DIR__ . '/composer/autoload_real.php'; 21 21 22 return ComposerAutoloaderInit 9d2e53dbd8e249f7f93d214afa9c4522::getLoader();22 return ComposerAutoloaderInit7bc26ac187e3e5b59cfcfcf02aeed97e::getLoader(); -
mass-email-notifications-for-gravity-forms/tags/1.3.6/vendor/composer/autoload_aliases.php
r3420036 r3422687 1 1 <?php 2 2 3 // Functions and constants 4 namespace GravityOps\Core\Admin { 5 if(!function_exists('\\GravityOps\\Core\\Admin\\gravityops_shell')){ 6 function gravityops_shell(...$args) { 7 return \MENFGF\GravityOps\Core\Admin\gravityops_shell(...func_get_args()); 8 } 9 } 10 } 3 11 4 12 -
mass-email-notifications-for-gravity-forms/tags/1.3.6/vendor/composer/autoload_files.php
r3420036 r3422687 9 9 '8d50dc88e56bace65e1e72f6017983ed' => $vendorDir . '/freemius/wordpress-sdk/start.php', 10 10 '9387666eac3fc37c9ef87deb087980c6' => $vendorDir . '/MENFGF/autoload.php', 11 '79fa1c9a31d9f4c8c1a536bd9e014492' => $vendorDir . '/MENFGF/gravityops/core/src/Admin/functions.php', 11 12 ); -
mass-email-notifications-for-gravity-forms/tags/1.3.6/vendor/composer/autoload_real.php
r3420881 r3422687 3 3 // autoload_real.php @generated by Composer 4 4 5 class ComposerAutoloaderInit 9d2e53dbd8e249f7f93d214afa9c45225 class ComposerAutoloaderInit7bc26ac187e3e5b59cfcfcf02aeed97e 6 6 { 7 7 private static $loader; … … 25 25 require __DIR__ . '/platform_check.php'; 26 26 27 spl_autoload_register(array('ComposerAutoloaderInit 9d2e53dbd8e249f7f93d214afa9c4522', 'loadClassLoader'), true, true);27 spl_autoload_register(array('ComposerAutoloaderInit7bc26ac187e3e5b59cfcfcf02aeed97e', 'loadClassLoader'), true, true); 28 28 self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); 29 spl_autoload_unregister(array('ComposerAutoloaderInit 9d2e53dbd8e249f7f93d214afa9c4522', 'loadClassLoader'));29 spl_autoload_unregister(array('ComposerAutoloaderInit7bc26ac187e3e5b59cfcfcf02aeed97e', 'loadClassLoader')); 30 30 31 31 require __DIR__ . '/autoload_static.php'; 32 call_user_func(\Composer\Autoload\ComposerStaticInit 9d2e53dbd8e249f7f93d214afa9c4522::getInitializer($loader));32 call_user_func(\Composer\Autoload\ComposerStaticInit7bc26ac187e3e5b59cfcfcf02aeed97e::getInitializer($loader)); 33 33 34 34 $loader->register(true); 35 35 36 $filesToLoad = \Composer\Autoload\ComposerStaticInit 9d2e53dbd8e249f7f93d214afa9c4522::$files;36 $filesToLoad = \Composer\Autoload\ComposerStaticInit7bc26ac187e3e5b59cfcfcf02aeed97e::$files; 37 37 $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { 38 38 if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { -
mass-email-notifications-for-gravity-forms/tags/1.3.6/vendor/composer/autoload_static.php
r3420881 r3422687 5 5 namespace Composer\Autoload; 6 6 7 class ComposerStaticInit 9d2e53dbd8e249f7f93d214afa9c45227 class ComposerStaticInit7bc26ac187e3e5b59cfcfcf02aeed97e 8 8 { 9 9 public static $files = array ( 10 10 '8d50dc88e56bace65e1e72f6017983ed' => __DIR__ . '/..' . '/freemius/wordpress-sdk/start.php', 11 11 '9387666eac3fc37c9ef87deb087980c6' => __DIR__ . '/..' . '/MENFGF/autoload.php', 12 '79fa1c9a31d9f4c8c1a536bd9e014492' => __DIR__ . '/..' . '/MENFGF/gravityops/core/src/Admin/functions.php', 12 13 ); 13 14 … … 19 20 { 20 21 return \Closure::bind(function () use ($loader) { 21 $loader->classMap = ComposerStaticInit 9d2e53dbd8e249f7f93d214afa9c4522::$classMap;22 $loader->classMap = ComposerStaticInit7bc26ac187e3e5b59cfcfcf02aeed97e::$classMap; 22 23 23 24 }, null, ClassLoader::class); -
mass-email-notifications-for-gravity-forms/tags/1.3.6/vendor/composer/installed.json
r3420881 r3422687 59 59 { 60 60 "name": "gravityops/core", 61 "version": "1.0. 18",62 "version_normalized": "1.0. 18.0",61 "version": "1.0.21", 62 "version_normalized": "1.0.21.0", 63 63 "source": { 64 64 "type": "git", 65 65 "url": "git@github.com:Eitan-brightleaf/gravityops.git", 66 "reference": " a74352489b658ed6a7f1c588abb2e18aae065a68"66 "reference": "5d859a7cca5cf8c1e469c80a88e755fb1be7c522" 67 67 }, 68 68 "dist": { 69 69 "type": "zip", 70 "url": "https://api.github.com/repos/Eitan-brightleaf/gravityops/zipball/ a74352489b658ed6a7f1c588abb2e18aae065a68",71 "reference": " a74352489b658ed6a7f1c588abb2e18aae065a68",70 "url": "https://api.github.com/repos/Eitan-brightleaf/gravityops/zipball/5d859a7cca5cf8c1e469c80a88e755fb1be7c522", 71 "reference": "5d859a7cca5cf8c1e469c80a88e755fb1be7c522", 72 72 "shasum": "" 73 73 }, … … 75 75 "php": ">=7.4" 76 76 }, 77 "time": "2025-12-1 6T09:58:09+00:00",77 "time": "2025-12-18T07:45:02+00:00", 78 78 "type": "library", 79 79 "installation-source": "source", -
mass-email-notifications-for-gravity-forms/tags/1.3.6/vendor/composer/installed.php
r3420881 r3422687 4 4 'pretty_version' => 'dev-main', 5 5 'version' => 'dev-main', 6 'reference' => ' f0ab76d4401e26cd5563866f07e0110432efba26',6 'reference' => '4b921b3009464563093dfd512b32f402b1533e6b', 7 7 'type' => 'library', 8 8 'install_path' => __DIR__ . '/../../', … … 14 14 'pretty_version' => 'dev-main', 15 15 'version' => 'dev-main', 16 'reference' => ' f0ab76d4401e26cd5563866f07e0110432efba26',16 'reference' => '4b921b3009464563093dfd512b32f402b1533e6b', 17 17 'type' => 'library', 18 18 'install_path' => __DIR__ . '/../../', … … 30 30 ), 31 31 'gravityops/core' => array( 32 'pretty_version' => '1.0. 18',33 'version' => '1.0. 18.0',34 'reference' => ' a74352489b658ed6a7f1c588abb2e18aae065a68',32 'pretty_version' => '1.0.21', 33 'version' => '1.0.21.0', 34 'reference' => '5d859a7cca5cf8c1e469c80a88e755fb1be7c522', 35 35 'type' => 'library', 36 36 'install_path' => __DIR__ . '/../gravityops/core', -
mass-email-notifications-for-gravity-forms/trunk/class-mass-email-notifications-for-gravity-forms.php
r3420209 r3422687 8 8 use MENFGF\GravityOps\Core\Utils\AssetHelper; 9 9 use MENFGF\GravityOps\Core\Admin\AdminShell; 10 use function MENFGF\GravityOps\Core\Admin\gravityops_shell; 10 11 if ( !defined( 'ABSPATH' ) ) { 11 12 exit; … … 206 207 parent::init_admin(); 207 208 // Register the new GravityOps AdminShell page under the parent menu. 208 AdminShell::instance()->register_plugin_page( $this->_slug, [209 gravityops_shell()->register_plugin_page( $this->_slug, [ 209 210 'title' => $this->_title, 210 211 'menu_title' => $this->_short_title, … … 326 327 */ 327 328 public function gops_render_suppressions() { 329 $groups = $this->get_structured_suppressions(); 328 330 echo '<div class="gops-card">'; 329 echo '<h2 class="gops-title" style="margin:0 0 8px;">Suppressions</h2>'; 330 if ( !method_exists( $this, 'get_structured_suppressions' ) ) { 331 echo '<p>Suppression list is not available.</p>'; 332 echo '</div>'; 333 return; 334 } 335 $groups = $this->get_structured_suppressions(); 336 if ( empty( $groups ) || !is_array( $groups ) ) { 331 echo '<h2 class="gops-title" style="margin:0 0 8px;">Suppressions (' . count( $groups ) . ')</h2>'; 332 if ( empty( $groups ) ) { 337 333 echo '<p>No suppressed emails found.</p>'; 338 334 echo '</div>'; … … 2267 2263 header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) ); 2268 2264 echo '<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">' . '<title>Unsubscribed</title>' . '<style>body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;line-height:1.5;padding:40px;background:#f6f7f9;color:#1d2327} .menfgf-unsub{max-width:560px;margin:40px auto;background:#fff;border:1px solid #ccd0d4;border-radius:8px;padding:24px;box-shadow:0 3px 8px rgba(0,0,0,.05)} .menfgf-unsub h1{font-size:20px;margin:0 0 8px} .menfgf-unsub p{margin:8px 0 0;color:#3c434a}</style></head><body>' . '<div class="menfgf-unsub"><h1>You have been unsubscribed</h1><p>You will no longer receive these mass email notifications from this site. You can close this tab.</p></div>' . '</body></html>'; 2269 wp_die();2265 exit; 2270 2266 } 2271 2267 … … 2960 2956 false, 2961 2957 false, 2962 $disable_auto_format2958 !$disable_auto_format 2963 2959 ); 2964 2960 $this->log_debug( __METHOD__ . '() - processed text ' . $processed_text ); -
mass-email-notifications-for-gravity-forms/trunk/mass-email-notifications-for-gf.php
r3420881 r3422687 6 6 * Author URI: https://brightleafdigital.io/ 7 7 * Description: Allows you to send notifications to everyone who filled out any of your forms. 8 * Version: 1.3. 58 * Version: 1.3.6 9 9 * Author: BrightLeaf Digital 10 10 * License: GPL-2.0+ … … 13 13 * @package MassEmailNotificationsForGravityForms 14 14 */ 15 use MENFGF\GravityOps\Core\Admin\AdminShell; 15 16 if ( !defined( 'ABSPATH' ) ) { 16 17 exit; … … 18 19 } 19 20 require_once __DIR__ . '/vendor/autoload.php'; 21 // Instantiate this plugin's copy of the AdminShell early so provider negotiation can happen on plugins_loaded. 22 add_action( 'plugins_loaded', function () { 23 AdminShell::instance(); 24 }, 1 ); 20 25 if ( function_exists( 'menfgf_fs' ) ) { 21 26 menfgf_fs()->set_basename( false, __FILE__ ); … … 66 71 } 67 72 menfgf_fs()->add_filter( 'enable_cpt_advanced_menu_logic', '__return_true' ); 68 define( 'MASS_EMAIL_NOTIFICATIONS_FOR_GRAVITY_FORMS_VERSION', '1.3. 5' );73 define( 'MASS_EMAIL_NOTIFICATIONS_FOR_GRAVITY_FORMS_VERSION', '1.3.6' ); 69 74 define( 'MASS_EMAIL_NOTIFICATIONS_FOR_GRAVITY_FORMS_BASENAME', plugin_basename( __FILE__ ) ); 70 75 add_action( 'admin_notices', function () { -
mass-email-notifications-for-gravity-forms/trunk/readme.txt
r3420881 r3422687 2 2 Tested up to: 6.9 3 3 Tags: GravityForms, notifications, email, task management, automation 4 Stable tag: 1.3. 54 Stable tag: 1.3.6 5 5 Requires PHP: 8.0 6 6 License: GPLv2 or later … … 44 44 == Changelog == 45 45 46 = 1.3.6 | Dec 18, 2025 = 47 * Fixed a bug in the new plugin menu where installed plugins would show as uninstalled 48 * Fixed some PHP error warnings 49 * Fixed a 500 response error returned when someone unsubscribed without a landing page configured 50 * Fixed a bug preventing auto formatting being disabled in some circumstances 51 46 52 = 1.3.5 | Dec 16, 2025 = 47 53 * Fixed another bug in new plugin menu … … 62 68 * Added shortocde support for premium and agency plans. 63 69 * Added a GravityFlow workflow step for premium and agency plans. 64 65 = 1.3.1 =66 * A few small quality of life improvements.67 68 = 1.3.0 =69 * A host of small UI/UX enhancements.70 * Added unsubscribe management features.71 * Added double opt-in management features.72 73 = 1.2.9 =74 * Fixed a bug where feed labels would not always display in the batch table. -
mass-email-notifications-for-gravity-forms/trunk/vendor/MENFGF/autoload.php
r3420881 r3422687 20 20 require_once __DIR__ . '/composer/autoload_real.php'; 21 21 22 return ComposerAutoloaderInit 0fa87d9e4ab62c721e5fc11d03c1d808::getLoader();22 return ComposerAutoloaderInitf3a8ee65c4639a42d5f2af71ff334aaa::getLoader(); -
mass-email-notifications-for-gravity-forms/trunk/vendor/MENFGF/composer/autoload_real.php
r3420881 r3422687 3 3 // autoload_real.php @generated by Composer 4 4 5 class ComposerAutoloaderInit 0fa87d9e4ab62c721e5fc11d03c1d8085 class ComposerAutoloaderInitf3a8ee65c4639a42d5f2af71ff334aaa 6 6 { 7 7 private static $loader; … … 25 25 require __DIR__ . '/platform_check.php'; 26 26 27 spl_autoload_register(array('ComposerAutoloaderInit 0fa87d9e4ab62c721e5fc11d03c1d808', 'loadClassLoader'), true, true);27 spl_autoload_register(array('ComposerAutoloaderInitf3a8ee65c4639a42d5f2af71ff334aaa', 'loadClassLoader'), true, true); 28 28 self::$loader = $loader = new \MENFGF\Composer\Autoload\ClassLoader(\dirname(__DIR__)); 29 spl_autoload_unregister(array('ComposerAutoloaderInit 0fa87d9e4ab62c721e5fc11d03c1d808', 'loadClassLoader'));29 spl_autoload_unregister(array('ComposerAutoloaderInitf3a8ee65c4639a42d5f2af71ff334aaa', 'loadClassLoader')); 30 30 31 31 require __DIR__ . '/autoload_static.php'; 32 call_user_func(\MENFGF\Composer\Autoload\ComposerStaticInit 0fa87d9e4ab62c721e5fc11d03c1d808::getInitializer($loader));32 call_user_func(\MENFGF\Composer\Autoload\ComposerStaticInitf3a8ee65c4639a42d5f2af71ff334aaa::getInitializer($loader)); 33 33 34 34 $loader->setClassMapAuthoritative(true); -
mass-email-notifications-for-gravity-forms/trunk/vendor/MENFGF/composer/autoload_static.php
r3420881 r3422687 5 5 namespace MENFGF\Composer\Autoload; 6 6 7 class ComposerStaticInit 0fa87d9e4ab62c721e5fc11d03c1d8087 class ComposerStaticInitf3a8ee65c4639a42d5f2af71ff334aaa 8 8 { 9 9 public static $prefixLengthsPsr4 = array ( … … 36 36 { 37 37 return \Closure::bind(function () use ($loader) { 38 $loader->prefixLengthsPsr4 = ComposerStaticInit 0fa87d9e4ab62c721e5fc11d03c1d808::$prefixLengthsPsr4;39 $loader->prefixDirsPsr4 = ComposerStaticInit 0fa87d9e4ab62c721e5fc11d03c1d808::$prefixDirsPsr4;40 $loader->classMap = ComposerStaticInit 0fa87d9e4ab62c721e5fc11d03c1d808::$classMap;38 $loader->prefixLengthsPsr4 = ComposerStaticInitf3a8ee65c4639a42d5f2af71ff334aaa::$prefixLengthsPsr4; 39 $loader->prefixDirsPsr4 = ComposerStaticInitf3a8ee65c4639a42d5f2af71ff334aaa::$prefixDirsPsr4; 40 $loader->classMap = ComposerStaticInitf3a8ee65c4639a42d5f2af71ff334aaa::$classMap; 41 41 42 42 }, null, ClassLoader::class); -
mass-email-notifications-for-gravity-forms/trunk/vendor/MENFGF/composer/installed.json
r3420881 r3422687 3 3 "1": { 4 4 "name": "gravityops/core", 5 "version": "1.0. 18",6 "version_normalized": "1.0. 18.0",5 "version": "1.0.21", 6 "version_normalized": "1.0.21.0", 7 7 "source": { 8 8 "type": "git", 9 9 "url": "git@github.com:Eitan-brightleaf/gravityops.git", 10 "reference": " a74352489b658ed6a7f1c588abb2e18aae065a68"10 "reference": "5d859a7cca5cf8c1e469c80a88e755fb1be7c522" 11 11 }, 12 12 "dist": { 13 13 "type": "zip", 14 "url": "https://api.github.com/repos/Eitan-brightleaf/gravityops/zipball/ a74352489b658ed6a7f1c588abb2e18aae065a68",15 "reference": " a74352489b658ed6a7f1c588abb2e18aae065a68",14 "url": "https://api.github.com/repos/Eitan-brightleaf/gravityops/zipball/5d859a7cca5cf8c1e469c80a88e755fb1be7c522", 15 "reference": "5d859a7cca5cf8c1e469c80a88e755fb1be7c522", 16 16 "shasum": "" 17 17 }, … … 19 19 "php": ">=7.4" 20 20 }, 21 "time": "2025-12-1 6T09:58:09+00:00",21 "time": "2025-12-18T07:45:02+00:00", 22 22 "type": "library", 23 23 "installation-source": "source", -
mass-email-notifications-for-gravity-forms/trunk/vendor/MENFGF/composer/installed.php
r3420881 r3422687 5 5 'pretty_version' => 'dev-main', 6 6 'version' => 'dev-main', 7 'reference' => ' f0ab76d4401e26cd5563866f07e0110432efba26',7 'reference' => '4b921b3009464563093dfd512b32f402b1533e6b', 8 8 'type' => 'library', 9 9 'install_path' => __DIR__ . '/../', … … 17 17 'gravityops/core' => 18 18 array ( 19 'pretty_version' => '1.0. 18',20 'version' => '1.0. 18.0',21 'reference' => ' a74352489b658ed6a7f1c588abb2e18aae065a68',19 'pretty_version' => '1.0.21', 20 'version' => '1.0.21.0', 21 'reference' => '5d859a7cca5cf8c1e469c80a88e755fb1be7c522', 22 22 'type' => 'library', 23 23 'install_path' => __DIR__ . '/../gravityops/core', -
mass-email-notifications-for-gravity-forms/trunk/vendor/MENFGF/gravityops/core/src/Admin/AdminShell.php
r3420881 r3422687 16 16 17 17 /** 18 * Library/core version used for provider negotiation. 19 * The highest version across loaded copies should be selected as provider. 20 */ 21 public const CORE_VERSION = '1.0.21'; 22 23 /** 18 24 * Holds the singleton instance. 19 25 * … … 21 27 */ 22 28 private static ?AdminShell $instance = null; 29 30 /** 31 * Tracks whether the chosen provider has already booted (registered hooks). 32 * Prevents multiple copies from attaching side‑effect hooks. 33 * 34 * @var bool 35 */ 36 private static bool $did_boot = false; 23 37 24 38 /** … … 35 49 * Get singleton instance. 36 50 */ 37 public static function instance(): AdminShell { 38 // First, try to get a shared instance provided by any loaded copy via filter. 51 public static function instance() { 52 // New: negotiate best provider by highest version (cross‑namespace). 53 $best = apply_filters( 'gravityops_shell_provider', null ); 54 if ( is_array( $best ) && isset( $best['shell'] ) ) { 55 return $best['shell']; 56 } 57 58 // Legacy: try a shared instance provided by any copy. 39 59 $shared = apply_filters( 'gravityops_shell_instance', null ); 40 60 if ( $shared instanceof self ) { 41 61 return $shared; 42 62 } 63 43 64 if ( null === self::$instance ) { 44 65 self::$instance = new self(); … … 53 74 */ 54 75 private function __construct() { 55 // Cross-namespace shared instance resolver: first provider wins. 56 $existing = apply_filters( 'gravityops_shell_instance', null ); 57 if ( $existing && $existing !== $this ) { 58 // Another copy has already provided an instance; avoid duplicate hooks. 59 return; 60 } 61 62 // Expose this instance for other namespaces/copies to reuse. 76 // Expose this instance for other namespaces/copies to reuse (legacy "first copy wins"). 63 77 add_filter( 64 78 'gravityops_shell_instance', … … 69 83 ); 70 84 71 // Defer adding menus until after all plugins have registered. 72 add_action( 'admin_menu', [ $this, 'register_menus' ], 99 ); 73 // Do NOT hide submenus by default; users reported accessibility issues. 74 // If needed in the future, this can be reintroduced behind a filter. 75 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] ); 85 // Versioned provider negotiation: highest version wins. 86 add_filter( 87 'gravityops_shell_provider', 88 function ( $best ) { 89 $mine = [ 90 'version' => self::CORE_VERSION, 91 'shell' => $this, 92 ]; 93 if ( ! is_array( $best ) || empty( $best['version'] ) ) { 94 return $mine; 95 } 96 return version_compare( (string) $mine['version'], (string) $best['version'], '>' ) ? $mine : $best; 97 }, 98 1 99 ); 100 101 // Defer side‑effect hooks until we negotiate the best provider. 102 // Each copy registers this, but only the selected provider will actually boot. 103 // If instantiated after plugins_loaded has already fired, boot immediately. 104 if ( function_exists( 'did_action' ) && did_action( 'plugins_loaded' ) ) { 105 $this->maybe_boot(); 106 } else { 107 add_action( 'plugins_loaded', [ $this, 'maybe_boot' ], 20 ); 108 } 76 109 } 77 110 … … 84 117 * @return bool True if the page exists. 85 118 */ 86 public static function has_page( string $slug ): bool{119 public static function has_page( $slug ) { 87 120 $provider = apply_filters( 'gravityops_shell_instance', null ); 88 121 if ( $provider instanceof self ) { … … 112 145 * @return array<string,array<string,string>> Tabs config array suitable to merge with register_plugin_page() tabs. 113 146 */ 114 public static function freemius_tabs( string $plugin_slug, array $labels = [] ): array{147 public static function freemius_tabs( $plugin_slug, $labels = [] ) { 115 148 $default_labels = [ 116 149 'account' => 'Account', … … 164 197 * @return void 165 198 */ 166 public static function render_feeds_list( array $feeds_and_forms, string $gf_subview_slug, string $plugin_short_title, string $toggle_action ): void{199 public static function render_feeds_list( $feeds_and_forms, $gf_subview_slug, $plugin_short_title, $toggle_action ) { 167 200 echo '<div class="gops-card">'; 168 201 echo '<h2 class="gops-title" style="margin:0 0 10px;">' . esc_html( $plugin_short_title ) . ' Feeds</h2>'; … … 224 257 * @return void 225 258 */ 226 public static function process_feed_toggle( string $action_prefix, string$return_url ) {259 public static function process_feed_toggle( $action_prefix, $return_url ) { 227 260 if ( empty( wp_unslash( $_SERVER['REQUEST_METHOD'] ) ) || 'POST' !== ( wp_unslash( $_SERVER['REQUEST_METHOD'] ) ?? '' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized 228 261 wp_safe_redirect( admin_url( $return_url ) ); … … 262 295 * @return void 263 296 */ 264 public static function render_help_tab( array $links ): void{297 public static function render_help_tab( $links ) { 265 298 echo '<div class="gops-card">'; 266 299 echo '<h2 class="gops-title" style="margin:0 0 8px;">Help</h2>'; … … 282 315 * @param array $args Page configuration. 283 316 */ 284 public function register_plugin_page( string $slug, array $args ): void { 285 // If another copy is the active provider, forward registration to it. 317 public function register_plugin_page( $slug, $args ) { 318 // If another copy is the active provider (new negotiation), forward registration to it first. 319 $best = apply_filters( 'gravityops_shell_provider', null ); 320 if ( is_array( $best ) && isset( $best['shell'] ) && $best['shell'] !== $this && is_object( $best['shell'] ) && method_exists( $best['shell'], 'register_plugin_page' ) ) { 321 $best['shell']->register_plugin_page( $slug, $args ); 322 return; 323 } 324 // Legacy shared-instance forwarding as a fallback. 286 325 $provider = apply_filters( 'gravityops_shell_instance', null ); 287 326 if ( $provider && $provider !== $this && is_object( $provider ) && method_exists( $provider, 'register_plugin_page' ) ) { 288 // Call method on the provider (may be a different class/namespace).289 327 $provider->register_plugin_page( $slug, $args ); 290 328 return; … … 304 342 * Add the submenu pages under the shared GravityOps parent. 305 343 */ 306 public function register_menus() : void{344 public function register_menus() { 307 345 if ( class_exists( __NAMESPACE__ . '\\SuiteMenu' ) ) { 308 346 SuiteMenu::ensure_parent_menu(); … … 342 380 * @param string $hook Current admin page hook. 343 381 */ 344 public function enqueue_assets( $hook ) : void{382 public function enqueue_assets( $hook ) { 345 383 $page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended 346 384 … … 375 413 376 414 /** 415 * Boot the chosen provider (register side‑effect hooks). Called once. 416 * 417 * @return void 418 */ 419 private function boot() { 420 if ( self::$did_boot ) { 421 return; 422 } 423 // Defer adding menus until after all plugins have registered. 424 add_action( 'admin_menu', [ $this, 'register_menus' ], 99 ); 425 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] ); 426 self::$did_boot = true; 427 } 428 429 /** 430 * On plugins_loaded, negotiate the best provider and boot only that one. 431 * Each copy registers this callback, but only the selected provider acts. 432 * 433 * @return void 434 */ 435 public function maybe_boot() { 436 if ( self::$did_boot ) { 437 return; 438 } 439 $best = apply_filters( 'gravityops_shell_provider', null ); 440 if ( is_array( $best ) && isset( $best['shell'] ) ) { 441 if ( $best['shell'] === $this ) { 442 $this->boot(); 443 } 444 return; 445 } 446 // If no provider negotiation is available, fall back to local boot (legacy environments). 447 $shared = apply_filters( 'gravityops_shell_instance', null ); 448 if ( $shared && $shared !== $this ) { 449 // Another copy is acting as shared instance; let it boot on its own call. 450 return; 451 } 452 $this->boot(); 453 } 454 455 /** 377 456 * Render the complete page including header, pills, and tab content. 378 457 * … … 380 459 * @param array $args Page config. 381 460 */ 382 public function render_page( string $slug, array $args ): void{461 public function render_page( $slug, $args ) { 383 462 if ( ! current_user_can( $args['capability'] ?? 'manage_options' ) ) { 384 463 return; … … 435 514 * @return void 436 515 */ 437 private function render_header_only( array $args ): void{516 private function render_header_only( $args ) { 438 517 ?> 439 518 <header class="gops-header"> … … 471 550 * @return array{css:string,js:string} 472 551 */ 473 public static function resolve_assets_urls() : array{552 public static function resolve_assets_urls() { 474 553 $base_url = apply_filters( 'gravityops_assets_base_url', '' ); 475 554 $css = ''; -
mass-email-notifications-for-gravity-forms/trunk/vendor/MENFGF/gravityops/core/src/Admin/SuiteMenu.php
r3420881 r3422687 30 30 */ 31 31 private static $did_notice_hook = false; 32 33 /** 34 * Track whether the parent GravityOps menu has already been registered. 35 * Prevents duplicate add_menu_page() calls and ensures a single owner of the parent page. 36 * 37 * @var bool 38 */ 39 private static $did_parent_menu = false; 32 40 33 41 /** … … 55 63 */ 56 64 public static function ensure_parent_menu( $capability = '' ) { 57 global $menu; 58 59 $menu_slug = 'gravity_ops'; 60 61 // If another plugin in the suite has already created the menu, we don't need to do anything. 62 if ( ! empty( $menu ) && in_array( $menu_slug, array_column( $menu, 2 ), true ) ) { 63 return; 65 global $menu; 66 67 $menu_slug = 'gravity_ops'; 68 69 // Internal idempotency guard — if we've already added the parent once this request, bail. 70 if ( self::$did_parent_menu ) { 71 return; 72 } 73 74 // If another plugin in the suite has already created the menu, we don't need to do anything. 75 if ( ! empty( $menu ) && in_array( $menu_slug, array_column( $menu, 2 ), true ) ) { 76 return; 64 77 } 65 78 … … 128 141 if ( $hook ) { 129 142 add_action( 'load-' . $hook, [ self::class, 'maybe_handle_plugin_toggle' ] ); 130 } 143 } 144 145 // Mark parent as registered to avoid duplicate add_menu_page calls in mixed environments. 146 self::$did_parent_menu = true; 131 147 132 148 // Ensure assets are enqueued at the proper time and only on our screen. … … 134 150 add_action( 'admin_enqueue_scripts', [ self::class, 'enqueue_assets' ] ); 135 151 self::$did_enqueue_hook = true; 136 }152 } 137 153 138 154 // Register admin notices renderer (error/success messages from actions below). … … 140 156 add_action( 'admin_notices', [ self::class, 'render_admin_notices' ] ); 141 157 self::$did_notice_hook = true; 142 }158 } 143 159 } 144 160 … … 173 189 $updates_count = 0; 174 190 175 // Annotate registry items with runtime state .191 // Annotate registry items with runtime state (supports premium/free variant pairs). 176 192 foreach ( $registry as $key => $item ) { 177 193 $type = $item['type'] ?? 'plugin'; … … 179 195 continue; 180 196 } 181 182 $file = $item['plugin_file']; 183 $is_installed = isset( $installed_plugins[ $file ] ); 184 $is_active = $is_installed && is_plugin_active( $file ); 185 $version = $is_installed ? ( $installed_plugins[ $file ]['Version'] ?? '' ) : ''; 186 187 $has_update = isset( $update_response[ $file ] ); 188 if ( $has_update ) { 197 $primary_file = (string) $item['plugin_file']; 198 $premium_file = isset( $item['plugin_files']['premium'] ) ? (string) $item['plugin_files']['premium'] : ''; 199 $free_file = isset( $item['plugin_files']['free'] ) ? (string) $item['plugin_files']['free'] : ''; 200 201 // Helper to read state for a specific plugin file 202 $read_state = function ( string $file ) use ( $installed_plugins, $update_response ) { 203 $installed = isset( $installed_plugins[ $file ] ); 204 $active = $installed && is_plugin_active( $file ); 205 $version = $installed ? ( $installed_plugins[ $file ]['Version'] ?? '' ) : ''; 206 $has_upd = isset( $update_response[ $file ] ); 207 $new_ver = $has_upd ? ( $update_response[ $file ]->new_version ?? '' ) : ''; 208 return [ $installed, $active, $version, $has_upd, $new_ver ]; 209 }; 210 211 // Default path: single-file plugins 212 if ( empty( $premium_file ) && empty( $free_file ) ) { 213 [ $is_installed, $is_active, $version, $has_update, $new_version ] = $read_state( $primary_file ); 214 if ( $has_update ) { 215 ++$updates_count; 216 } 217 $registry[ $key ]['is_installed'] = $is_installed; 218 $registry[ $key ]['is_active'] = $is_active; 219 $registry[ $key ]['version'] = $version; 220 $registry[ $key ]['has_update'] = $has_update; 221 $registry[ $key ]['new_version'] = $new_version; 222 $registry[ $key ]['plugin_file_active'] = $is_active ? $primary_file : ''; 223 $registry[ $key ]['plugin_file_action'] = $primary_file; 224 $registry[ $key ]['uses_free'] = false; 225 continue; 226 } 227 228 // Variant-aware path: prefer premium when present 229 $is_installed_prem = false; 230 $is_active_prem = false; 231 $ver_prem = ''; 232 $upd_prem = false; 233 $new_prem = ''; 234 $is_installed_free = false; 235 $is_active_free = false; 236 $ver_free = ''; 237 $upd_free = false; 238 $new_free = ''; 239 240 if ( $premium_file ) { 241 [ $is_installed_prem, $is_active_prem, $ver_prem, $upd_prem, $new_prem ] = $read_state( $premium_file ); 242 } 243 if ( $free_file ) { 244 [ $is_installed_free, $is_active_free, $ver_free, $upd_free, $new_free ] = $read_state( $free_file ); 245 } 246 247 $is_installed = $is_installed_prem || $is_installed_free; 248 $is_active = $is_active_prem || $is_active_free; 249 $uses_free = false; 250 $version = ''; 251 $file_active = ''; 252 $has_update = false; 253 $new_version = ''; 254 255 // Choose versions and update flags based on precedence 256 if ( $is_active_prem ) { 257 $file_active = $premium_file; 258 $version = $ver_prem; 259 } elseif ( $is_active_free ) { 260 $file_active = $free_file; 261 $version = $ver_free; 262 $uses_free = true; 263 } elseif ( $is_installed_prem ) { 264 $version = $ver_prem; 265 } elseif ( $is_installed_free ) { 266 $version = $ver_free; 267 $uses_free = true; // Only free exists → show Free badge 268 } 269 270 // Updates: consider whichever is installed; prefer premium if both 271 if ( $upd_prem || $upd_free ) { 272 $has_update = $upd_prem || $upd_free; 273 $new_version = $upd_prem ? $new_prem : $new_free; 189 274 ++$updates_count; 190 275 } 191 276 192 $registry[ $key ]['is_installed'] = $is_installed; 193 $registry[ $key ]['is_active'] = $is_active; 194 $registry[ $key ]['version'] = $version; 195 $registry[ $key ]['has_update'] = $has_update; 196 $registry[ $key ]['new_version'] = $has_update ? ( $update_response[ $file ]->new_version ?? '' ) : ''; 277 // Activation target: if active → target the active file for deactivation. 278 // If inactive → prefer premium when installed; else free. 279 if ( $is_active ) { 280 $file_action = $file_active ?: ( $is_installed_prem ? $premium_file : $free_file ); 281 } else { 282 $file_action = $is_installed_prem ? $premium_file : ( $free_file ?: $premium_file ); 283 } 284 285 $registry[ $key ]['is_installed'] = $is_installed; 286 $registry[ $key ]['is_active'] = $is_active; 287 $registry[ $key ]['version'] = $version; 288 $registry[ $key ]['has_update'] = $has_update; 289 $registry[ $key ]['new_version'] = $new_version; 290 $registry[ $key ]['plugin_file_active'] = $file_active; 291 $registry[ $key ]['plugin_file_action'] = $file_action ?: $primary_file; 292 $registry[ $key ]['uses_free'] = $uses_free; 197 293 } 198 294 … … 319 415 <?php echo $is_active ? 'Active' : ( $is_installed ? 'Inactive' : 'Not Installed' ); ?> 320 416 </span> 417 <?php if ( ! empty( $item['uses_free'] ) ) : ?> 418 <span class="gops-badge">Free</span> 419 <?php endif; ?> 321 420 <?php if ( $version ) : ?> 322 421 <span class="gops-tile__version">v<?php echo esc_html( $version ); ?></span> … … 331 430 <?php if ( current_user_can( 'activate_plugins' ) ) : ?> 332 431 <form class="gops-action" method="post" action="<?php echo esc_url( $base_url ); ?>"> 333 <?php wp_nonce_field( 'gops_toggle_' . $item['plugin_file'], 'gops_nonce' ); ?>432 <?php wp_nonce_field( 'gops_toggle_' . ( $item['plugin_file_action'] ?? $item['plugin_file'] ), 'gops_nonce' ); ?> 334 433 <input type="hidden" name="gops-action" value="<?php echo $is_active ? 'deactivate' : 'activate'; ?>" /> 335 <input type="hidden" name="plugin" value="<?php echo esc_attr( $i tem['plugin_file']); ?>" />434 <input type="hidden" name="plugin" value="<?php echo esc_attr( $is_active ? ( $item['plugin_file_active'] ?: ( $item['plugin_file_action'] ?? $item['plugin_file'] ) ) : ( $item['plugin_file_action'] ?? $item['plugin_file'] ) ); ?>" /> 336 435 <button class="button<?php echo $is_active ? '' : ' button-primary'; ?>" type="submit"><?php echo $is_active ? 'Deactivate' : 'Activate'; ?></button> 337 436 </form> … … 358 457 * @return string Icon URL or empty string if none found. 359 458 */ 360 private static function resolve_plugin_icon_url( array $item ): string{459 private static function resolve_plugin_icon_url( $item ) { 361 460 $url = apply_filters( 'gravityops_plugin_icon_url', '', $item ); 362 461 if ( ! empty( $url ) ) { … … 422 521 * @return void 423 522 */ 424 public static function enqueue_assets( $hook ) : void{523 public static function enqueue_assets( $hook ) { 425 524 $page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended 426 525 $is_gravityops_screen = ( false !== strpos( (string) $hook, 'gravity_ops' ) ) || ( 'gravity_ops' === $page ); … … 452 551 * @return void 453 552 */ 454 public static function render_admin_notices() : void{553 public static function render_admin_notices() { 455 554 $is_gravityops_screen = isset( $_GET['page'] ) && 'gravity_ops' === sanitize_key( wp_unslash( $_GET['page'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended 456 555 if ( ! $is_gravityops_screen ) { -
mass-email-notifications-for-gravity-forms/trunk/vendor/MENFGF/gravityops/core/src/SuiteRegistry.php
r3420036 r3422687 25 25 * 'description', 'marketing_url', 'docs_url', 'is_free', and 'icon_html'. 26 26 */ 27 public static function all() : array{27 public static function all() { 28 28 // NOTE: External links are placeholders. Replace with final URLs where marked. 29 29 return [ … … 54 54 'slug' => 'integrate-asana-with-gravity-forms', 55 55 'plugin_file' => 'integrate-asana-with-gravity-forms/integrate-asana-with-gravity-forms.php', 56 // Free + Premium variants: prefer premium folder when present 57 'plugin_files' => [ 58 'premium' => 'integrate-asana-with-gravity-forms-premium/integrate-asana-with-gravity-forms.php', 59 'free' => 'integrate-asana-with-gravity-forms/integrate-asana-with-gravity-forms.php', 60 ], 56 61 'name' => 'Integrate Asana with Gravity Forms', 57 62 'description' => 'Turn form submissions into Asana tasks instantly.', … … 65 70 'slug' => 'mass_email_notifications_for_gf', 66 71 'plugin_file' => 'mass-email-notifications-for-gravity-forms/mass-email-notifications-for-gf.php', 72 // Free + Premium variants: prefer premium folder when present 73 'plugin_files' => [ 74 'premium' => 'mass-email-notifications-for-gravity-forms-premium/mass-email-notifications-for-gf.php', 75 'free' => 'mass-email-notifications-for-gravity-forms/mass-email-notifications-for-gf.php', 76 ], 67 77 'name' => 'Mass Email Notifications', 68 78 'description' => 'Send bulk emails to Gravity Forms entries.', … … 75 85 'type' => 'plugin', 76 86 'slug' => 'kanban-view-for-gravity-view', 77 'plugin_file' => 'kanban-view-for-gravity-view /kanban-view-for-gv.php',87 'plugin_file' => 'kanban-view-for-gravity-view-premium/kanban-view-for-gv.php', 78 88 'name' => 'Kanban View for GravityView', 79 89 'description' => 'Turn GravityView into a kanban project board.', … … 86 96 'type' => 'plugin', 87 97 'slug' => 'Recurring_Form_Submissions_For_Gravity_Form', 88 'plugin_file' => 'recurring-form-submissions-for-gravity-forms /recurring-form-submissions-for-gravity-form.php',98 'plugin_file' => 'recurring-form-submissions-for-gravity-forms-premium/recurring-form-submissions-for-gravity-form.php', 89 99 'name' => 'Recurring Form Submissions', 90 100 'description' => 'Schedule recurring Gravity Forms submissions.', … … 97 107 'type' => 'plugin', 98 108 'slug' => 'gravity_ops_global_variables', 99 'plugin_file' => 'global-variables-for-gravity-math/global-variables-for-gravity-math.php', 109 // Premium-only plugin uses a -premium folder suffix 110 'plugin_file' => 'global-variables-for-gravity-math-premium/global-variables-for-gravity-math.php', 100 111 'name' => 'Global Variables', 101 112 'description' => 'Create shared variables for GravityMath formulas.', -
mass-email-notifications-for-gravity-forms/trunk/vendor/autoload.php
r3420881 r3422687 20 20 require_once __DIR__ . '/composer/autoload_real.php'; 21 21 22 return ComposerAutoloaderInit 9d2e53dbd8e249f7f93d214afa9c4522::getLoader();22 return ComposerAutoloaderInit7bc26ac187e3e5b59cfcfcf02aeed97e::getLoader(); -
mass-email-notifications-for-gravity-forms/trunk/vendor/composer/autoload_aliases.php
r3420036 r3422687 1 1 <?php 2 2 3 // Functions and constants 4 namespace GravityOps\Core\Admin { 5 if(!function_exists('\\GravityOps\\Core\\Admin\\gravityops_shell')){ 6 function gravityops_shell(...$args) { 7 return \MENFGF\GravityOps\Core\Admin\gravityops_shell(...func_get_args()); 8 } 9 } 10 } 3 11 4 12 -
mass-email-notifications-for-gravity-forms/trunk/vendor/composer/autoload_files.php
r3420036 r3422687 9 9 '8d50dc88e56bace65e1e72f6017983ed' => $vendorDir . '/freemius/wordpress-sdk/start.php', 10 10 '9387666eac3fc37c9ef87deb087980c6' => $vendorDir . '/MENFGF/autoload.php', 11 '79fa1c9a31d9f4c8c1a536bd9e014492' => $vendorDir . '/MENFGF/gravityops/core/src/Admin/functions.php', 11 12 ); -
mass-email-notifications-for-gravity-forms/trunk/vendor/composer/autoload_real.php
r3420881 r3422687 3 3 // autoload_real.php @generated by Composer 4 4 5 class ComposerAutoloaderInit 9d2e53dbd8e249f7f93d214afa9c45225 class ComposerAutoloaderInit7bc26ac187e3e5b59cfcfcf02aeed97e 6 6 { 7 7 private static $loader; … … 25 25 require __DIR__ . '/platform_check.php'; 26 26 27 spl_autoload_register(array('ComposerAutoloaderInit 9d2e53dbd8e249f7f93d214afa9c4522', 'loadClassLoader'), true, true);27 spl_autoload_register(array('ComposerAutoloaderInit7bc26ac187e3e5b59cfcfcf02aeed97e', 'loadClassLoader'), true, true); 28 28 self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); 29 spl_autoload_unregister(array('ComposerAutoloaderInit 9d2e53dbd8e249f7f93d214afa9c4522', 'loadClassLoader'));29 spl_autoload_unregister(array('ComposerAutoloaderInit7bc26ac187e3e5b59cfcfcf02aeed97e', 'loadClassLoader')); 30 30 31 31 require __DIR__ . '/autoload_static.php'; 32 call_user_func(\Composer\Autoload\ComposerStaticInit 9d2e53dbd8e249f7f93d214afa9c4522::getInitializer($loader));32 call_user_func(\Composer\Autoload\ComposerStaticInit7bc26ac187e3e5b59cfcfcf02aeed97e::getInitializer($loader)); 33 33 34 34 $loader->register(true); 35 35 36 $filesToLoad = \Composer\Autoload\ComposerStaticInit 9d2e53dbd8e249f7f93d214afa9c4522::$files;36 $filesToLoad = \Composer\Autoload\ComposerStaticInit7bc26ac187e3e5b59cfcfcf02aeed97e::$files; 37 37 $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { 38 38 if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { -
mass-email-notifications-for-gravity-forms/trunk/vendor/composer/autoload_static.php
r3420881 r3422687 5 5 namespace Composer\Autoload; 6 6 7 class ComposerStaticInit 9d2e53dbd8e249f7f93d214afa9c45227 class ComposerStaticInit7bc26ac187e3e5b59cfcfcf02aeed97e 8 8 { 9 9 public static $files = array ( 10 10 '8d50dc88e56bace65e1e72f6017983ed' => __DIR__ . '/..' . '/freemius/wordpress-sdk/start.php', 11 11 '9387666eac3fc37c9ef87deb087980c6' => __DIR__ . '/..' . '/MENFGF/autoload.php', 12 '79fa1c9a31d9f4c8c1a536bd9e014492' => __DIR__ . '/..' . '/MENFGF/gravityops/core/src/Admin/functions.php', 12 13 ); 13 14 … … 19 20 { 20 21 return \Closure::bind(function () use ($loader) { 21 $loader->classMap = ComposerStaticInit 9d2e53dbd8e249f7f93d214afa9c4522::$classMap;22 $loader->classMap = ComposerStaticInit7bc26ac187e3e5b59cfcfcf02aeed97e::$classMap; 22 23 23 24 }, null, ClassLoader::class); -
mass-email-notifications-for-gravity-forms/trunk/vendor/composer/installed.json
r3420881 r3422687 59 59 { 60 60 "name": "gravityops/core", 61 "version": "1.0. 18",62 "version_normalized": "1.0. 18.0",61 "version": "1.0.21", 62 "version_normalized": "1.0.21.0", 63 63 "source": { 64 64 "type": "git", 65 65 "url": "git@github.com:Eitan-brightleaf/gravityops.git", 66 "reference": " a74352489b658ed6a7f1c588abb2e18aae065a68"66 "reference": "5d859a7cca5cf8c1e469c80a88e755fb1be7c522" 67 67 }, 68 68 "dist": { 69 69 "type": "zip", 70 "url": "https://api.github.com/repos/Eitan-brightleaf/gravityops/zipball/ a74352489b658ed6a7f1c588abb2e18aae065a68",71 "reference": " a74352489b658ed6a7f1c588abb2e18aae065a68",70 "url": "https://api.github.com/repos/Eitan-brightleaf/gravityops/zipball/5d859a7cca5cf8c1e469c80a88e755fb1be7c522", 71 "reference": "5d859a7cca5cf8c1e469c80a88e755fb1be7c522", 72 72 "shasum": "" 73 73 }, … … 75 75 "php": ">=7.4" 76 76 }, 77 "time": "2025-12-1 6T09:58:09+00:00",77 "time": "2025-12-18T07:45:02+00:00", 78 78 "type": "library", 79 79 "installation-source": "source", -
mass-email-notifications-for-gravity-forms/trunk/vendor/composer/installed.php
r3420881 r3422687 4 4 'pretty_version' => 'dev-main', 5 5 'version' => 'dev-main', 6 'reference' => ' f0ab76d4401e26cd5563866f07e0110432efba26',6 'reference' => '4b921b3009464563093dfd512b32f402b1533e6b', 7 7 'type' => 'library', 8 8 'install_path' => __DIR__ . '/../../', … … 14 14 'pretty_version' => 'dev-main', 15 15 'version' => 'dev-main', 16 'reference' => ' f0ab76d4401e26cd5563866f07e0110432efba26',16 'reference' => '4b921b3009464563093dfd512b32f402b1533e6b', 17 17 'type' => 'library', 18 18 'install_path' => __DIR__ . '/../../', … … 30 30 ), 31 31 'gravityops/core' => array( 32 'pretty_version' => '1.0. 18',33 'version' => '1.0. 18.0',34 'reference' => ' a74352489b658ed6a7f1c588abb2e18aae065a68',32 'pretty_version' => '1.0.21', 33 'version' => '1.0.21.0', 34 'reference' => '5d859a7cca5cf8c1e469c80a88e755fb1be7c522', 35 35 'type' => 'library', 36 36 'install_path' => __DIR__ . '/../gravityops/core',
Note: See TracChangeset
for help on using the changeset viewer.