PluginProbe
Easy Search Replace – Find & Replace Text/HTML/URLs, Remove Footer Credit / 1.3.1
Easy Search Replace – Find & Replace Text/HTML/URLs, Remove Footer Credit v1.3.1
1.3.1 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2.0 1.2.1 1.2.2 1.3.0
easy-search-replace / easy-search-replace.php

easy-search-replace.php in Easy Search Replace – Find & Replace Text/HTML/URLs, Remove Footer Credit 1.3.1, at easy-search-replace.php

212 lines 9.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Plugin Name: Easy Search Replace
5 * Description: Find & replace text, HTML, or URLs across your WordPress site in real time — no database changes. Pro adds regex, scheduling, live preview, analytics, role/device targeting, exclusions, and sync.
6 * Version: 1.3.1
7 * Author: FluxPress
8 * Author URI: https://fluxpress.io
9 * Text Domain: easy-search-replace
10 * Domain Path: /languages
11 * License: GNU General Public License v2 or later
12 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
13 * Requires at least: 5.0
14 * Requires PHP: 7.2
15 *
16 * @package EasySearchReplace
17 */
18 // Exit if accessed directly.
19 if ( !defined( 'ABSPATH' ) ) {
20 exit;
21 }
22 /* ---------------------------------------------------------------------------
23 * Coexistence guard
24 *
25 * The free and Pro builds share the same class/constant names. If BOTH are
26 * installed and active in the same request, loading the second copy would
27 * redeclare everything and fatal. So: if another copy already loaded this
28 * request, bail out of this one.
29 *
30 * Additionally, if THIS copy is the Pro build, deactivate the free build so the
31 * next request loads Pro cleanly. Rules/settings live in the same option
32 * (esrn_search_replace_options), so nothing is lost either way.
33 * ------------------------------------------------------------------------- */
34 if ( defined( 'ESRN_VERSION' ) ) {
35 // Physical check (not the ESRN_FORCE_FREE simulation): does THIS copy carry
36 // the Pro-only files? If so, it's the Pro build and should take over.
37 if ( file_exists( __DIR__ . '/inc/pro/class-scheduler__premium_only.php' ) && is_admin() ) {
38 if ( !function_exists( 'deactivate_plugins' ) ) {
39 require_once ABSPATH . 'wp-admin/includes/plugin.php';
40 }
41 deactivate_plugins( 'easy-search-replace/easy-search-replace.php' );
42 // activate_plugin() captured the active-plugins list BEFORE including this
43 // file and writes it back AFTER — silently re-activating free. The
44 // 'activated_plugin' hook fires after that write, so deactivate again there.
45 add_action( 'activated_plugin', function () {
46 deactivate_plugins( 'easy-search-replace/easy-search-replace.php' );
47 }, 0 );
48 }
49 return;
50 }
51 /* ---------------------------------------------------------------------------
52 * Plugin constants
53 * ------------------------------------------------------------------------- */
54 if ( !defined( 'ESRN_VERSION' ) ) {
55 define( 'ESRN_VERSION', '1.3.1' );
56 }
57 if ( !defined( 'ESRN_PLUGIN_FILE' ) ) {
58 define( 'ESRN_PLUGIN_FILE', __FILE__ );
59 }
60 if ( !defined( 'ESRN_PLUGIN_DIR' ) ) {
61 define( 'ESRN_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
62 }
63 if ( !defined( 'ESRN_PLUGIN_URL' ) ) {
64 define( 'ESRN_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
65 }
66 if ( !defined( 'ESRN_PLUGIN_BASENAME' ) ) {
67 define( 'ESRN_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
68 }
69 if ( !defined( 'ESRN_OPTION_KEY' ) ) {
70 define( 'ESRN_OPTION_KEY', 'esrn_search_replace_options' );
71 }
72 /* ---------------------------------------------------------------------------
73 * Freemius SDK bootstrap
74 *
75 * Freemius handles: license-key activation, automatic Pro lock-out the moment
76 * a license expires / is deactivated / is cancelled, and updates for licensed
77 * installs. It replaces the previous SureCart licensing + updater entirely.
78 *
79 * The array is pre-filled with this product's ID (28354) and public key. If
80 * you regenerate the snippet in the Freemius dashboard
81 * (Product 28354 → Settings → "WordPress SDK"), copy its `slug` /
82 * `premium_slug` values here so they match the dashboard exactly.
83 * ------------------------------------------------------------------------- */
84 if ( !function_exists( 'esr_fs' ) ) {
85 /**
86 * Create/return the singleton Freemius instance.
87 *
88 * @return Freemius
89 */
90 function esr_fs() {
91 global $esr_fs;
92 if ( !isset( $esr_fs ) ) {
93 // Load the SDK.
94 require_once ESRN_PLUGIN_DIR . 'freemius/start.php';
95 /*
96 * Reliable free-vs-premium build detection. Freemius does NOT flip the
97 * `is_premium` config flag when it generates the free build, so we cannot
98 * hardcode it — otherwise the free build still behaves as Pro (pops the
99 * license-activation modal). The `__premium_only` files ARE physically
100 * stripped from the free build, so their presence is the source of truth.
101 * Drive BOTH is_premium and anonymous_mode from it, so Freemius' own
102 * behaviour stays in sync with ESRN_License_Gate::is_premium_build().
103 */
104 $esrn_is_premium_build = file_exists( ESRN_PLUGIN_DIR . 'inc/pro/class-scheduler__premium_only.php' ) && !(defined( 'ESRN_FORCE_FREE' ) && ESRN_FORCE_FREE);
105 // dev: fully simulate the free build from source.
106 $esr_fs = fs_dynamic_init( array(
107 'id' => '28354',
108 'slug' => 'easy-search-replace',
109 'premium_slug' => 'easy-search-replace-pro',
110 'type' => 'plugin',
111 'public_key' => 'pk_9b2e8b8a3228f372ccc9548cfb273',
112 'is_premium' => false,
113 'premium_suffix' => 'Pro',
114 'has_addons' => false,
115 'has_paid_plans' => true,
116 'is_org_compliant' => true,
117 'trial' => array(
118 'days' => 3,
119 'is_require_payment' => true,
120 ),
121 'menu' => array(
122 'slug' => 'easy_search_replace',
123 'account' => true,
124 'contact' => false,
125 'support' => false,
126 'parent' => array(
127 'slug' => 'options-general.php',
128 ),
129 ),
130 'anonymous_mode' => !$esrn_is_premium_build,
131 'is_live' => true,
132 ) );
133 }
134 return $esr_fs;
135 }
136
137 // Init Freemius.
138 esr_fs();
139 // Signal that the SDK is ready (other code may hook esr_fs()->add_filter()).
140 do_action( 'esr_fs_loaded' );
141 /**
142 * Hide the Freemius-added "Upgrade" (pricing) submenu under Settings →
143 * Easy Search Replace. Upgrades are driven from our own CTAs / License tab.
144 *
145 * @param bool $is_visible Whether the submenu item is visible.
146 * @param string $menu_id The submenu id.
147 * @return bool
148 */
149 function esrn_fs_hide_upgrade_submenu( $is_visible, $menu_id ) {
150 if ( 'pricing' === $menu_id ) {
151 return false;
152 }
153 return $is_visible;
154 }
155
156 esr_fs()->add_filter(
157 'is_submenu_visible',
158 'esrn_fs_hide_upgrade_submenu',
159 10,
160 2
161 );
162 /*
163 * Suppress Freemius' "start a trial" promotion — specifically the little
164 * blue "1" counter bubble it stamps on the Settings → Easy Search Replace
165 * menu item (and its matching promo notice). Users still reach the trial
166 * from the sales page / License tab; we just don't nag with a fake counter.
167 * The `show_trial` filter stops it going forward; the admin_init cleanup
168 * clears an already-set sticky on installs that saw the bubble before this.
169 */
170 esr_fs()->add_filter( 'show_trial', '__return_false' );
171 /**
172 * Clear a previously-set trial-promotion sticky (and thus its menu bubble).
173 * Runs before Freemius' own _add_trial_notice (admin_init @10), so with
174 * show_trial disabled the bubble is gone the same request. No-op once clear.
175 */
176 function esrn_fs_clear_trial_bubble() {
177 if ( !class_exists( 'FS_Admin_Notices' ) ) {
178 return;
179 }
180 $notices = FS_Admin_Notices::instance( 'easy-search-replace' );
181 if ( is_object( $notices ) && method_exists( $notices, 'has_sticky' ) && $notices->has_sticky( 'trial_promotion' ) ) {
182 $notices->remove_sticky( 'trial_promotion' );
183 }
184 }
185
186 add_action( 'admin_init', 'esrn_fs_clear_trial_bubble', 5 );
187 }
188 /* ---------------------------------------------------------------------------
189 * Load plugin classes and modules
190 * ------------------------------------------------------------------------- */
191 require_once ESRN_PLUGIN_DIR . 'inc/class-rule-schema.php';
192 require_once ESRN_PLUGIN_DIR . 'inc/class-license-gate.php';
193 // The License tab is a Pro-only screen. Its file is stripped from the free
194 // build by Freemius, so guard the require — the free build never loads it.
195 $esrn_license_tab = ESRN_PLUGIN_DIR . 'inc/admin/tab-license__premium_only.php';
196 if ( file_exists( $esrn_license_tab ) ) {
197 require_once $esrn_license_tab;
198 }
199 unset($esrn_license_tab);
200 require_once ESRN_PLUGIN_DIR . 'inc/class-rule-engine.php';
201 require_once ESRN_PLUGIN_DIR . 'inc/class-selector-engine.php';
202 require_once ESRN_PLUGIN_DIR . 'inc/options.php';
203 require_once ESRN_PLUGIN_DIR . 'lib/dom.php';
204 /* ---------------------------------------------------------------------------
205 * Procedural hooks & bootstrap
206 *
207 * Kept in a separate, require_once'd file (not inline) so the coexistence guard
208 * above can actually prevent a second copy from loading them. PHP hoists
209 * top-level function declarations at compile time, which a runtime `return`
210 * cannot stop — a required file is only compiled when the require runs.
211 * ------------------------------------------------------------------------- */
212 require_once ESRN_PLUGIN_DIR . 'inc/hooks.php';