├── .github
└── CODEOWNERS
├── .gitignore
├── .scrutinizer.yml
├── CONTRIBUTING.md
├── Gruntfile.js
├── LICENSE.txt
├── Makefile
├── README.txt
├── assets
├── css
│ ├── better-search-replace.css
│ ├── images
│ │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png
│ │ ├── ui-bg_diagonals-thick_20_666666_40x40.png
│ │ ├── ui-bg_flat_10_000000_40x100.png
│ │ ├── ui-bg_glass_100_f6f6f6_1x400.png
│ │ ├── ui-bg_glass_100_fdf5ce_1x400.png
│ │ ├── ui-bg_glass_65_ffffff_1x400.png
│ │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png
│ │ ├── ui-bg_highlight-soft_100_eeeeee_1x100.png
│ │ ├── ui-bg_highlight-soft_75_ffe45c_1x100.png
│ │ ├── ui-icons_222222_256x240.png
│ │ ├── ui-icons_228ef1_256x240.png
│ │ ├── ui-icons_ef8c08_256x240.png
│ │ ├── ui-icons_ffd27a_256x240.png
│ │ └── ui-icons_ffffff_256x240.png
│ └── jquery-ui.min.css
├── img
│ ├── bsr-logo-white.svg
│ ├── phil-gravatar.jpeg
│ └── sidebar-upgrade.png
├── index.php
├── js
│ └── better-search-replace.js
└── svg
│ ├── icon-arrow.svg
│ ├── icon-checkmark.svg
│ ├── icon-help.svg
│ ├── icon-upgrade.svg
│ ├── logo-bsr.svg
│ └── mdb-birds.svg
├── better-search-replace.php
├── build-cfg
├── better-search-replace
│ ├── config.php
│ ├── filter
│ ├── filter.php
│ ├── pre-zip.php
│ └── version-check.php
├── build-plugin.sh
└── utils
│ ├── create-json.php
│ ├── get_plugin_version.php
│ └── get_plugin_zip_name.php
├── ext
├── bsr-ext-functions.php
└── class-bsr-plugin-updater.php
├── includes
├── class-bsr-admin.php
├── class-bsr-ajax.php
├── class-bsr-compatibility.php
├── class-bsr-db.php
├── class-bsr-i18n.php
├── class-bsr-loader.php
├── class-bsr-main.php
├── class-bsr-plugin-footer.php
├── class-bsr-templates-helper.php
├── class-bsr-utils.php
└── index.php
├── index.php
├── languages
├── better-search-replace-de_DE.mo
├── better-search-replace-de_DE.po
├── better-search-replace-es_ES.mo
├── better-search-replace-es_ES.po
├── better-search-replace-fr_FR.mo
├── better-search-replace-fr_FR.po
└── better-search-replace.pot
├── package.json
├── templates
├── bsr-dashboard.php
├── bsr-help.php
├── bsr-search-replace.php
├── bsr-settings.php
└── sidebar.php
├── vendor
└── brumann
│ └── polyfill-unserialize
│ ├── LICENSE
│ └── src
│ ├── DisallowedClassesSubstitutor.php
│ └── Unserialize.php
└── yarn.lock
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @deliciousbrains/deli-eng
2 |
3 | #jira:DELI is where issues related to this repository should be ticketed]
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Operating Systems
2 | Thumbs.db
3 | ehthumbs.db
4 | Desktop.ini
5 | $RECYCLE.BIN/
6 | .DS_Store
7 | *~
8 |
9 | # IDEs
10 | *.sublime-project
11 | *.sublime-workspace
12 | .idea
13 | *.pydevproject
14 | .project
15 | .metadata
16 | build/
17 | tmp/
18 | tests/clover.xml
19 |
20 | # Node
21 | node_modules
22 |
23 | # Artifacts
24 | builds/
25 | assets/css/better-search-replace.min.css
26 | assets/js/better-search-replace.min.*
27 |
--------------------------------------------------------------------------------
/.scrutinizer.yml:
--------------------------------------------------------------------------------
1 | # .scrutinizer.yml
2 | tools:
3 | external_code_coverage: true
4 | sensiolabs_security_checker: true
5 | php_mess_detector: true
6 | php_code_sniffer: true
7 | php_code_coverage: true
8 | php_sim: true
9 | php_analyzer: true
10 | php_pdepend: true
11 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | #Contributing to Better Search Replace
2 |
3 | Better Search Replace is open source to encourage feedback and community patches.
4 |
5 | Please check the guidelines below before contributing to make sure that everything stays in order.
6 |
7 | __Please Note:__ GitHub is for bug reports and contributions only - if you have a support question please don't post here, go to the [Support Forum](https://wordpress.org/support/plugin/better-search-replace) instead.
8 |
9 | ## Getting Started
10 |
11 | * Submit a ticket for your issue, assuming one does not already exist.
12 | * Raise it on the [Issue Tracker](https://github.com/deliciousbrains/Better-Search-Replace/issues)
13 | * Clearly describe the issue including steps to reproduce the bug.
14 | * Make sure you fill in the earliest version that you know has the issue as well as the version of WordPress you're using.
15 |
16 | ## Making Changes
17 |
18 | * Fork the repository on GitHub
19 | * Make the changes to your forked repository
20 | * Ensure you stick to the [WordPress Coding Standards](https://codex.wordpress.org/WordPress_Coding_Standards)
21 | * When committing, reference your issue (if present) and include a note about the fix
22 | * If possible, and if applicable, please also add/update unit tests for your changes
23 | * Push the changes to your fork and submit a pull request to the 'master' branch of the repository
24 |
25 | ## Code Documentation
26 |
27 | * Please make sure that every function is documented!
28 | * If you're adding/editing a function in a class, make sure to add `@access {private|public|protected}`
29 | * Finally, please use tabs and not spaces. The tab indent size should be 4 for all code.
30 |
31 | Once you've submitted your pull request, it will be reviewed and merged in if all looks good.
32 |
33 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 | grunt.initConfig({
4 | pkg: grunt.file.readJSON('package.json'),
5 | makepot: {
6 | target: {
7 | options: {
8 | domainPath: '/languages/',
9 | mainFile: 'better-search-replace.php',
10 | potFilename: 'better-search-replace.pot',
11 | potHeaders: {
12 | poedit: true,
13 | 'report-msgid-bugs-to': 'http://wordpress.org/support/plugin/better-search-replace',
14 | 'last-translator': 'Delicious Brains ',
15 | 'language-team': 'Delicious Brains '
16 | },
17 | type: 'wp-plugin',
18 | updateTimestamp: true,
19 | }
20 | }
21 | },
22 | cssmin: {
23 | target: {
24 | files: [{
25 | expand: true,
26 | cwd: 'assets/css',
27 | src: ['*.css', '!*.min.css'],
28 | dest: 'assets/css',
29 | ext: '.min.css'
30 | }]
31 | }
32 | },
33 | uglify: {
34 | my_target: {
35 | options: {
36 | sourceMap: true
37 | },
38 | files: {
39 | 'assets/js/better-search-replace.min.js': ['assets/js/better-search-replace.js']
40 | }
41 | }
42 | },
43 | watch: {
44 | css: {
45 | files: [
46 | 'assets/css/*.css',
47 | '!assets/css/*.min.css'
48 | ],
49 | tasks: [
50 | 'cssmin'
51 | ]
52 | },
53 | js: {
54 | files: [
55 | 'assets/js/*.js',
56 | '!assets/js/*.min.js',
57 | '!assets/js/*.min.js.map'
58 | ],
59 | tasks: [
60 | 'uglify'
61 | ]
62 | }
63 | }
64 | });
65 |
66 | grunt.loadNpmTasks('grunt-wp-i18n');
67 | grunt.loadNpmTasks('grunt-contrib-cssmin');
68 | grunt.loadNpmTasks('grunt-contrib-uglify');
69 | grunt.loadNpmTasks('grunt-contrib-watch');
70 |
71 | };
72 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | PHP_SRC := better-search-replace.php $(wildcard includes/*.php) $(wildcard ext/*.php)
2 | POT_OBJ := languages/better-search-replace.pot
3 | CSS_DIR := assets/css
4 | CSS_ALL := $(wildcard $(CSS_DIR)/*.css)
5 | CSS_SRC := $(filter-out %.min.css,$(CSS_ALL))
6 | CSS_OBJ := $(CSS_SRC:.css=.min.css)
7 | JS_DIR := assets/js
8 | JS_ALL := $(wildcard $(JS_DIR)/*.js)
9 | JS_SRC := $(filter-out %.min.js,$(JS_ALL))
10 | JS_OBJ := $(JS_SRC:.js=.min.js)
11 | JS_MAP := $(JS_SRC:.js=.min.js.map)
12 |
13 | .PHONY: all
14 | all: build-translations build-css uglify
15 |
16 | .PHONY: build-translations
17 | build-translations: $(POT_OBJ)
18 |
19 | $(POT_OBJ): $(PHP_SRC) | node_modules
20 | grunt makepot
21 |
22 | .PHONY: build-css
23 | build-css: $(CSS_OBJ)
24 |
25 | $(CSS_OBJ): %.min.css: %.css | node_modules
26 | grunt cssmin
27 |
28 | .PHONY: uglify
29 | uglify: $(JS_OBJ)
30 |
31 | $(JS_OBJ): %.min.js: %.js | node_modules
32 | grunt uglify
33 |
34 | .PHONY: zip
35 | zip: all
36 | ./build-cfg/build-plugin.sh
37 |
38 | .PHONY: package
39 | package: zip
40 |
41 | .PHONY: install
42 | install: node_modules
43 |
44 | node_modules: package.json
45 | yarn install
46 |
47 | .PHONY: update-deps
48 | update-deps:
49 | yarn upgrade
50 |
51 | .PHONY: product-info
52 | product-info:
53 | php build-cfg/utils/create-json.php README.txt better-search-replace.php > builds/info.json
54 |
55 | .PHONY: clean
56 | clean:
57 | rm -rf builds
58 | rm -f $(CSS_OBJ)
59 | rm -f $(JS_OBJ) $(JS_MAP)
60 |
61 | .PHONY: clean-all
62 | clean-all: clean
63 | rm -rf node_modules
64 |
--------------------------------------------------------------------------------
/README.txt:
--------------------------------------------------------------------------------
1 | === Better Search Replace ===
2 | Contributors: wpengine, deliciousbrains, mattshaw
3 | Tags: search replace, search and replace, search replace database, update database urls, update live url
4 | Requires at least: 3.0.1
5 | Tested up to: 6.7
6 | Stable tag: 1.4.11-dev
7 | License: GPLv3 or later
8 | License URI: http://www.gnu.org/licenses/gpl-3.0.html
9 |
10 | A simple plugin to update URLs or other text in a database.
11 |
12 | == Description ==
13 |
14 | When moving your WordPress site to a new domain or server, you will likely run into a need to run a search/replace on the database for everything to work correctly. Fortunately, there are several plugins available for this task, however, all have a different approach to a few key features. This plugin consolidates the best features from these plugins, incorporating the following features in one simple plugin:
15 |
16 | * Serialization support for all tables
17 | * The ability to select specific tables
18 | * The ability to run a "dry run" to see how many fields will be updated
19 | * No server requirements aside from a running installation of WordPress
20 | * WordPress Multisite support
21 |
22 | > **Time-saving features available in the Pro version:**
23 | >
24 | > * View exactly what changed during a search/replace
25 | > * Backup and import the database while running a search/replace
26 | > * Priority email support from the developer of the plugin
27 | > * Save or load custom profiles for quickly repeating a search/replace in the future
28 | > * Support and updates for 1 year
29 | >
30 | > **[Learn more about Better Search Replace Pro](https://bettersearchreplace.com/)**
31 |
32 | The search and replace functionality is heavily based on interconnect/it's great and open-source Search Replace DB script, modified to use WordPress native database functions to ensure compatibility.
33 |
34 | **Supported Languages**
35 |
36 | * English
37 | * French
38 | * German
39 | * Spanish
40 |
41 | **Want to contribute?**
42 |
43 | Feel free to open an issue or submit a pull request on [GitHub](https://github.com/deliciousbrains/better-search-replace/).
44 |
45 | == Installation ==
46 |
47 | Install Better Search Replace like you would install any other WordPress plugin.
48 |
49 | Dashboard Method:
50 |
51 | 1. Login to your WordPress admin and go to Plugins -> Add New
52 | 2. Type "Better Search Replace" in the search bar and select this plugin
53 | 3. Click "Install", and then "Activate Plugin"
54 |
55 |
56 | Upload Method:
57 |
58 | 1. Unzip the plugin and upload the "better-search-replace" folder to your 'wp-content/plugins' directory
59 | 2. Activate the plugin through the Plugins menu in WordPress
60 |
61 | == Frequently Asked Questions ==
62 |
63 | = Using Better Search Replace =
64 |
65 | Once activated, Better Search Replace will add a page under the "Tools" menu page in your WordPress admin.
66 |
67 | = Is my host supported? =
68 |
69 | Yes! This plugin should be compatible with any host.
70 |
71 | = Can I damage my site with this plugin? =
72 |
73 | Yes! Entering a wrong search or replace string could damage your database. Because of this, it is always advisable to have a backup of your database before using this plugin.
74 |
75 | = How does this work on WordPress Multisite? =
76 |
77 | When this plugin is installed on a WordPress multisite network:
78 |
79 | * Subsite administrators can only search and replace within tables that belong to that subsite by visiting Dashboard > Tools > Better Search Replace from WP Admin of the subsite.
80 | * Network administrators (i.e. Super Admins) and administrators of the primary site can search and replace across all tables in the multisite network by visiting Dashboard > Tools > Better Search Replace from WP Admin of the primary site.
81 |
82 | To change which users have access to the plugin, the user capability can be modified via code using the `bsr_capability` filter.
83 |
84 | = How can I use this plugin when changing URLs? =
85 |
86 | If you're moving your site from one server to another and changing the URL of your WordPress installation, the approach below allows you to do so easily without affecting the old site:
87 |
88 | 1. Backup the database on your current site
89 | 2. Install the database on your new host
90 | 3. On the new host, define the new site URL in the `wp-config.php` file, as shown [here](http://codex.wordpress.org/Changing_The_Site_URL#Edit_wp-config.php)
91 | 4. Log in at your new admin URL and run Better Search Replace on the old site URL for the new site URL
92 | 5. Delete the site_url constant you added to `wp-config.php`. You may also need to regenerate your .htaccess by going to Settings -> Permalinks and saving the settings.
93 |
94 | More information on moving WordPress can be found [here](http://codex.wordpress.org/Moving_WordPress).
95 |
96 | == Screenshots ==
97 |
98 | 1. The Better Search Replace page added to the "Tools" menu
99 | 2. After running a search/replace dry-run.
100 |
101 | == Changelog ==
102 |
103 | = Unreleased =
104 |
105 | = 1.4.10 - January 14, 2025 =
106 | * Fix: Improved security and stability
107 |
108 | = 1.4.9 - October 4, 2024 =
109 | * Security: The plugin now uses its own update mechanism from WP Engine servers
110 | * New: Dependencies have been updated
111 |
112 | = 1.4.8 - September 3, 2024 =
113 | * No changes as this was a pro-only release for Better Search Replace Pro
114 |
115 | = 1.4.7 - May 30, 2024 =
116 | * Fix: The case-insensitive setting once again allows case-insensitive strings to be matched within serialized data, fixing a regression introduced in version 1.4.6
117 |
118 | = 1.4.6 - April 17, 2024 =
119 | * Changed: Serialized text strings are now only deserialized when containing a match, resulting in faster performance
120 | * Security: Table names are now escaped when displaying search results
121 |
122 | = 1.4.5 - January 18, 2024 =
123 | * Security: Unserializing an object during search and replace operations now passes `'allowed_classes' => false` to avoid instantiating the object and potentially running malicious code stored in the database (thanks to Wordfence for responsible disclosure on December 18, 2023 followed by development and testing of the fix by WP Engine)
124 | * Fix: A regression in version 1.4.4 which caused some search results to be skipped has been fixed to ensure only numeric keyed objects are skipped
125 |
126 | = 1.4.4 - December 14, 2023 =
127 | * Fix: Objects with numerical properties are now skipped to avoid causing errors
128 |
129 | = 1.4.3 - September 5, 2023 =
130 | * New: Links to plugin documentation, support, feedback, and changelog are now available in the footer of WP Admin
131 | * Improvement: PHP 8.2 and Better Search Replace are now compatible
132 |
133 | = 1.4.2 - January 11, 2023 =
134 | * Security: Arbitrary tab templates in the `templates` directory can no longer be loaded using a query parameter.
135 |
136 | = 1.4.1 - July 25, 2022 =
137 | * Security: Selected tables are now confirmed to exist before processing the request
138 |
139 | = 1.4 - April 7, 2022 =
140 | * New: Better Search Replace has a brand new user interface
141 | * Improvement: Default capability required to use the plugin has changed from "install_plugins" to "manage_options" for compatibility with DISALLOW_FILE_MODS
142 |
143 | = 1.3.4 - December 7, 2020 =
144 | * Improvement: WordPress 5.6 and PHP 8 compatible
145 | * Fix: Strings that have been serialized twice showing up as false-positives
146 |
147 | = 1.3.3 - February 26, 2019 =
148 | * Fix: Some special characters interfering with search/replace
149 | * Security: Pass template filenames through `sanitize_file_name()`
150 | * Security: Verify nonce when downloading diagnostic info
151 |
152 | = 1.3.2 - January 3, 2018 =
153 | * Fix: Only one table searched on some environments (props @Ov3rfly)
154 | * Tweak: Update text in sidebar
155 |
156 | = 1.3.1 - September 14, 2017 =
157 | * Security: Check if data is serialized before unserializing it
158 | * Improvement: Increased size of table select
159 |
160 | = 1.3 - November 10, 2016 =
161 | * Improvement: Updated sidebar and added pro version discount
162 | * Fix: Outdated links to old website
163 | * Fix: Prevent requests to invalid tabs
164 |
165 | = 1.2.10 - June 2, 2016 =
166 | * Fix: CSS not loaded on details page
167 |
168 | = 1.2.9 - December 8, 2015 =
169 | * Fix: Bug with case-insensitive searches in serialized objects
170 | * Fix: Bug with early skip due to lack of primary key
171 |
172 | = 1.2.8 - November 25, 2015 =
173 | * Fix: Bug with report details
174 |
175 | = 1.2.7 - November 24, 2015 =
176 | * Fix: Untranslateable string
177 | * Tweak: Check BSR_PATH instead of ABSPATH to be consistent
178 | * Tested with 4.4
179 |
180 | = 1.2.6 =
181 | * Removed unused code/small cleanup
182 |
183 | = 1.2.5 =
184 | * Improved progress bar info and styles
185 | * Small cleanup
186 |
187 | = 1.2.4 =
188 | * Added "Settings saved" notice when saving settings
189 | * Fixed bug with wp_magic_quotes interfering with some search strings
190 |
191 | = 1.2.3 =
192 | * Fixed bug with searching for backslashes
193 | * Fixed potential bug with getting tables in large multisites
194 | * Fixed potential notice in append_report
195 | * Improved handling of missing primary keys
196 |
197 | = 1.2.2 =
198 | * Fixed AJAX conflict with WooCommerce
199 | * Fixed a few issues with translations
200 | * Tweaked "System Info" to use get_locale() instead of WP_LANG constant
201 | * Updated German translation (props @Linus Ziegenhagen)
202 |
203 | = 1.2.1 =
204 | * Fixed minor issue with display of progress bar
205 | * Updated translation file
206 |
207 | = 1.2 =
208 | * Switched to AJAX bulk processing for search/replaces
209 | * Decreased minimum "Max Page Size" to 1000
210 | * Added "Help" tab with system info for easier troubleshooting
211 |
212 | = 1.1.1 =
213 | * Added ability to change max page size
214 | * Decreased default page size to prevent white screen issue on some environments
215 |
216 | = 1.1 =
217 | * Added ability to change capability required to use plugin
218 | * Small bugfixes and translation fixes
219 |
220 | = 1.0.6 =
221 | * Added table sizes to the database table listing
222 | * Added French translation (props @Jean Philippe)
223 |
224 | = 1.0.5 =
225 | * Added support for case-insensitive searches
226 | * Added German translation (props @Linus Ziegenhagen)
227 |
228 | = 1.0.4 =
229 | * Potential security fixes
230 |
231 | = 1.0.3 =
232 | * Fixed issue with searching for special characters like '\'
233 | * Fixed bug with replacing some objects
234 |
235 | = 1.0.2 =
236 | * Fixed untranslateable strings on submit button and submenu page.
237 |
238 | = 1.0.1 =
239 | * Fixed issue with loading translations and added Spanish translation (props Eduardo Larequi)
240 | * Fixed bug with reporting timing
241 | * Updated to use "Dry Run" as default
242 | * Added support for WordPress Multisite (see FAQs for more info)
243 |
244 | = 1.0 =
245 | * Initial release
246 |
--------------------------------------------------------------------------------
/assets/css/better-search-replace.css:
--------------------------------------------------------------------------------
1 | /*OLD STYLING----------------------------*/
2 |
3 | #bsr-results-table th { font-weight: bold; }
4 | #bsr-results-table tbody tr:nth-child(odd) { background-color: #F9F9F9; }
5 | .bsr-second, .bsr-third, .bsr-fourth { text-align: center !important; }
6 | #bsr-details-view-wrap { margin: 0 10px; }
7 | #bsr-details-view { table-layout: fixed; padding-top: 40px; }
8 | .bsr-old-val { background-color: #fdd; }
9 | .bsr-new-val { background-color: #cfc; }
10 | .bsr-change { width: 400px !important; }
11 | .bsr-slider { width: 23em; }
12 | .bsr-progress-wrap { width: 95%; height: 12px; background-color: #ddd; }
13 | .bsr-progress { width: 0%; height: 100%; background-color: #0073aa; }
14 | #bsr-search-replace-wrap {/* margin-top: 10px; */}
15 | .bsr-description { display: block; margin-top: 6px !important; color: #444 !important; }
16 | #bsr-help-heading { font-size: 1.3em !important; padding: 0 !important; }
17 | .bsr-processing-wrap { background: #f4f4f4; padding: 16px 16px 32px; overflow: auto; border-top: 1px solid #eae9e9; margin: 20px -12px -23px -12px; }
18 | .bsr-spinner { margin: -3px 0 0 0; }
19 | .bsr-license-status { float: left; margin-right: 15px; height: 28px; font-size: 13px; line-height: 26px; color: var(--color-white); text-align: center; padding: 0 10px; border-radius: 4px; }
20 | #bsr-license-active { background: green; }
21 | #bsr-license-inactive { background: gray; }
22 | .bsr-no-profiles { vertical-align: middle; }
23 | #bsr-back-to-overview { width: 100%; position: fixed; margin-top: 0; background: #f8f8f8; border-bottom: 1px solid #ddd; padding: 8px 10px; }
24 | #bsr-table-select { width:25em; height: 180px; }
25 |
26 |
27 | /*CSS VARIABLES----------------------------*/
28 | :root {
29 | /*colors*/
30 | --color-primary: #0073AA;
31 | --color-accent: #27CC87;
32 | --color-white: #fff;
33 | --color-black: 000;
34 | --color-header: #383A46;
35 | --color-nav: #262932;
36 | --color-body-text: #3C3B59;
37 | --color-desc-text: #6E6D99;
38 | --color-panel-heading: #708AA4;
39 | --color-secondary-hover: rgba(0, 115, 170, .15);
40 | --color-secondary-focus: rgba(0, 115, 170, .4);
41 | --color-divider: #CAD8EC;
42 | --color-divider-light: rgba(202, 216, 236, .5);
43 | --color-progress-bg: #57645E;
44 | --color-modal-background: rgba(47, 58, 74, .8);
45 |
46 | /*spacers*/
47 | --spacer-xs: 8px;
48 | --spacer-sm: 16px;
49 | --spacer-md: 24px;
50 | --spacer-lg: 32px;
51 | --spacer-xl: 40px;
52 | --spacer-2xl: 48px;
53 | --spacer-3xl: 56px;
54 | --spacer-4xl: 64px;
55 | --spacer-5xl: 72px;
56 | --spacer-6xl: 80px;
57 |
58 | /*layout*/
59 | --panel-border-radius: 6px;
60 |
61 | /*shadows*/
62 | --panel-shadow: 0px 2px 1px rgba(39, 45, 77, 0.05), 0px 2px 8px rgba(187, 187, 187, 0.20);
63 | --input-shadow: 0px 2px 2px rgba(182, 181, 204, 0.25);
64 | }
65 |
66 |
67 | /*WP OVERRIDES & WRAPPER STYLING----------------------------*/
68 |
69 | .wrap {
70 | margin: 0;
71 | padding: 0;
72 | overflow-x: auto!important;
73 | }
74 |
75 | #wpcontent {
76 | padding: 0!important;
77 | }
78 |
79 | #wpbody-content {
80 | background: var(--color-header);
81 | padding-bottom: 0!important;
82 | margin: 0 !important;
83 | float: none;
84 | }
85 |
86 | .form-table {
87 | margin-top: 0;
88 | }
89 |
90 | .wp-core-ui select {
91 | background: #fff url(data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M5%206l5%205%205-5%202%201-7%207-7-7%202-1z%22%20fill%3D%22%23555%22%2F%3E%3C%2Fsvg%3E) no-repeat right 12px top 55%;
92 | background-size: 18px 18px;
93 | }
94 |
95 | .metabox-holder {
96 | padding: 0!important;
97 | }
98 |
99 |
100 | /*MODAL OVERRIDES----------------------------*/
101 |
102 | #TB_overlay {
103 | background: var(--color-modal-background)!important;
104 | }
105 |
106 | #TB_window {
107 | background: var(--color-white);
108 | box-shadow: var(--panel-shadow);
109 | border-radius: var(--panel-border-radius);
110 | overflow: hidden;
111 | }
112 |
113 | #TB_title {
114 | display: flex;
115 | align-items: center;
116 | padding: 0 var(--spacer-lg);
117 | height: var(--spacer-3xl)!important;
118 | font-weight: 500!important;
119 | }
120 |
121 | #TB_ajaxWindowTitle {
122 | font-weight: 500;
123 | font-size: 14px;
124 | letter-spacing: 0.6px;
125 | text-transform: uppercase;
126 | color: var(--color-panel-heading);
127 | line-height: 1;
128 | padding:0!important;
129 | }
130 |
131 | .tb-close-icon {
132 | color: var(--color-panel-heading)!important;
133 | top: -14px!important;
134 | right: 12px!important;
135 | }
136 |
137 | #bsr-results-table {
138 | border-radius: var(--panel-border-radius)!important;
139 | }
140 |
141 | #bsr-results-table th {
142 | line-height: 2rem!important;
143 | }
144 |
145 | #bsr-results-table tbody tr:last-child td:first-of-type {
146 | border-bottom-left-radius: var(--panel-border-radius);
147 | }
148 |
149 | #bsr-results-table tbody tr:last-child td:last-of-type {
150 | border-bottom-right-radius: var(--panel-border-radius);
151 | }
152 |
153 | #bsr-results-table th {
154 | color: var(--color-header)!important;
155 | }
156 |
157 | #bsr-results-table td .tooltip {
158 | font-weight: bold;
159 | cursor: pointer;
160 | text-decoration: underline;
161 | }
162 |
163 | #bsr-results-table td .helper-message {
164 | max-width: 220px;
165 | }
166 |
167 | #bsr-results-table td .helper-message a {
168 | font-weight: bold;
169 | }
170 |
171 | #bsr-back-to-overview {
172 | padding: 16px!important;
173 | }
174 |
175 | #bsr-details-view {
176 | padding-top:48px;
177 | }
178 |
179 | .bsr-change {
180 | border-bottom: 1px solid var(--color-divider);
181 | padding-bottom: 16px!important;
182 | }
183 |
184 | .widefat td {
185 | padding: var(--spacer-sm);
186 | }
187 |
188 | .bsr-row-desc td {
189 | line-height: 2rem!important;
190 | padding-bottom: 0;
191 | font-size: 14px;
192 | }
193 |
194 |
195 | /*LAYOUT STYLING----------------------------*/
196 |
197 | .row {
198 | display: flex;
199 | column-gap: var(--spacer-lg);
200 | }
201 |
202 | .col {
203 | display: flex;
204 | flex-direction: column;
205 | justify-content: center;
206 | }
207 |
208 | .hidden {
209 | display: none;
210 | }
211 |
212 | .full-width {
213 | width: 100%;
214 | }
215 |
216 | .row p {
217 | margin: 0;
218 | }
219 |
220 |
221 | /*HEADER STYLING----------------------------*/
222 |
223 |
224 | .header {
225 | background: var(--color-header);
226 | display:flex;
227 | height: 96px;
228 | padding: 0 var(--spacer-lg);
229 | }
230 |
231 | .header a {
232 | display: flex;
233 | }
234 |
235 | .logo {
236 | width: 72px;
237 | }
238 |
239 | .header .content {
240 | display: flex;
241 | justify-content: space-between;
242 | align-items: center;
243 | max-width: 1280px;
244 | width: 100%;
245 | }
246 |
247 | .upgrade-notice {
248 | color: var(--color-accent);
249 | cursor: pointer;
250 | line-height: 1.3;
251 | font-size: 13.5px;
252 | font-weight: 500;
253 | }
254 |
255 | .upgrade-notice:hover {
256 | text-decoration: underline;
257 | color: var(--color-accent);
258 | }
259 |
260 | .upgrade-notice img {
261 | width: 16px;
262 | height: 16px;
263 | margin-right: var(--spacer-xs);
264 | }
265 |
266 | .update-nag, notice-warning-inline {
267 | margin: var(--spacer-md) var(--spacer-lg) 0 var(--spacer-lg);
268 | }
269 |
270 | .bsr-notice-container {
271 | padding: var(--spacer-sm) var(--spacer-lg) 0 var(--spacer-lg);
272 | max-width: 900px;
273 | }
274 |
275 | #setting-error-settings_updated,
276 | .bsr-updated {
277 | display: none;
278 | }
279 |
280 | /*NAV STYLING----------------------------*/
281 |
282 | .nav-tab-wrapper {
283 | font-size: 23px;
284 | height: var(--spacer-3xl);
285 | background: var(--color-nav);
286 | display: flex;
287 | padding: 0;
288 | align-items: center;
289 | margin: 0;
290 | }
291 |
292 | .nav-tab {
293 | color: var(--color-white);
294 | opacity: .5;
295 | border-top: 4px solid transparent !important;
296 | border-bottom: 4px solid transparent !important;
297 | }
298 |
299 | .nav-tab:hover {
300 | opacity: 1;
301 | background: none;
302 | color: var(--color-white);
303 | }
304 |
305 | .nav-tab:focus {
306 | background: none;
307 | color: var(--color-white);
308 | opacity: inherit;
309 | }
310 |
311 | .nav-tab-active {
312 | color: var(--color-white)! important;
313 | opacity: 1!important;
314 | border-bottom: 4px solid var(--color-accent) !important;
315 | }
316 |
317 | .nav-tab-wrapper ul {
318 | padding: 0 var(--spacer-lg);
319 | display: flex;
320 | column-gap: var(--spacer-lg);
321 | height: 100%;
322 | margin: 0;
323 | }
324 |
325 | .nav-tab-wrapper li {
326 | margin: 0;
327 | padding: 0;
328 | }
329 |
330 | .nav-tab-wrapper a {
331 | margin: 0;
332 | background: none;
333 | border: none;
334 | padding: 0;
335 | font-weight: 500 !important;
336 | align-items: center;
337 | display: inline-flex;
338 | height: 100%;
339 | box-sizing: border-box;
340 | }
341 |
342 |
343 | /*BUTTON STYLING----------------------------*/
344 |
345 | .button {
346 | font-size: 15px !important;
347 | letter-spacing: 0.4px !important;
348 | border-radius: var(--panel-border-radius) !important;
349 | font-weight: 500 !important;
350 | display: inline-flex !important;
351 | align-items: center !important;
352 | padding: 0 var(--spacer-md) !important;
353 | column-gap: 8px;
354 | margin: 0!important;
355 | }
356 |
357 | .button-lg {
358 | height: var(--spacer-3xl) !important;
359 | }
360 |
361 | .button-md {
362 | height: var(--spacer-2xl) !important;
363 | }
364 |
365 | .button-sm {
366 | height: var(--spacer-xl) !important;
367 | padding: 0 var(--spacer-sm) !important;
368 | font-size: 14px !important;
369 | border-radius: 4px!important;
370 | }
371 |
372 | .button-primary {
373 | color: var(--color-white) !important;
374 | background: var(--color-primary) !important;
375 | border: 1px solid !important;
376 | }
377 |
378 | .button-secondary {
379 | color: var(--color-primary) !important;
380 | background: transparent !important;
381 | border: 1px solid var(--color-primary) !important;
382 | }
383 |
384 | .button-primary:hover {
385 | filter: brightness(0.95) !important;
386 | }
387 |
388 | .button-primary:active {
389 | filter: brightness(0.92) !important;
390 | }
391 |
392 | .button-primary:focus {
393 | outline: none !important;
394 | box-shadow: 0 0 0 4px var(--color-secondary-focus) !important;
395 | }
396 |
397 | .button-secondary:hover {
398 | background: var(--color-secondary-hover) !important;
399 | }
400 |
401 | .button-active:active {
402 | outline: none !important;
403 | box-shadow: 0 0 0 4px var(--color-secondary-focus) !important;
404 | }
405 |
406 | .button-secondary:focus {
407 | outline: none !important;
408 | box-shadow: 0 0 0 4px var(--color-secondary-focus) !important;
409 | }
410 |
411 | .button-link {
412 | color: #2271b1;
413 | }
414 |
415 | .button svg {
416 | width: 16px;
417 | }
418 |
419 | #bsr-submit.bsr-disabled, #bsr-submit.button-disabled, #bsr-backup-submit.bsr-disabled, #bsr-backup-submit.button-disabled, #bsr-import-submit.bsr-disabled, #bsr-import-submit.button-disabled {
420 | background: var(--color-primary)!important;
421 | color: var(--color-white) !important;
422 | opacity: .4;
423 | }
424 |
425 |
426 | /*PLUGIN UI----------------------------*/
427 |
428 | .bsr-action-form {
429 | margin: 0!important;
430 | border: 0!important;
431 | background-color: rgb(240, 240, 241);
432 | box-shadow: none;
433 | padding: var(--spacer-2xl) var(--spacer-lg);
434 | padding-bottom: 120px;
435 | }
436 |
437 | .ui-sidebar-wrapper {
438 | max-width: 1280px;
439 | display: flex;
440 | flex-direction: row;
441 | column-gap: 48px;
442 | }
443 |
444 | #bsr-search-replace-wrap {
445 | background: transparent;
446 | border: 0;
447 | padding: 0;
448 | box-shadow: none;
449 | }
450 |
451 | #bsr-search-replace-form {
452 | display: flex;
453 | flex-direction: column;
454 | row-gap: var(--spacer-lg);
455 | }
456 |
457 | #bsr-search-replace-form .updated {
458 | margin-top: 0;
459 | margin-bottom: 0;
460 | display: block !important;
461 | }
462 |
463 | .inside {
464 | margin: 0!important;
465 | padding: 0!important;
466 | width: 100%;
467 | min-width: 640px;
468 | display: flex;
469 | flex-direction: column;
470 | row-gap: var(--spacer-lg);
471 | }
472 |
473 | .panel {
474 | background: var(--color-white);
475 | box-shadow: var(--panel-shadow);
476 | border-radius: var(--panel-border-radius);
477 | }
478 |
479 | .panel-header {
480 | height: 56px;
481 | padding: 0 var(--spacer-lg) !important;
482 | border-bottom: 1px solid var( --color-divider);
483 | display: flex;
484 | align-items: center;
485 | justify-content: space-between;
486 | }
487 |
488 | .panel-header a {
489 | display: inline-flex;
490 | }
491 |
492 | .panel-header h3 {
493 | font-weight: 500;
494 | font-size: 14px;
495 | letter-spacing: 0.6px;
496 | text-transform: uppercase;
497 | color: var(--color-panel-heading);
498 | line-height: 1;
499 | padding: 0!important;
500 | }
501 |
502 | .panel-footer {
503 | padding: var(--spacer-md) var(--spacer-lg);
504 | border-top: 1px solid var( --color-divider);
505 | }
506 |
507 | #bsr-error-wrap {
508 | display: none;
509 | }
510 |
511 | #bsr-error-wrap .error {
512 | margin: 0;
513 | }
514 |
515 | .bsr-processing-wrap {
516 | background: var(--color-white);
517 | box-shadow: var(--panel-shadow);
518 | border-radius: var(--panel-border-radius);
519 | margin: 0;
520 | padding: var(--spacer-lg);
521 | }
522 |
523 | .bsr-progress {
524 | height: var(--spacer-xs);
525 | border-radius: 20px;
526 | background: var(--color-accent);
527 | }
528 |
529 | .bsr-progress-wrap {
530 | height: var(--spacer-xs);
531 | }
532 |
533 | .panel-content {
534 | padding: var(--spacer-lg);
535 | display: flex;
536 | flex-direction: column;
537 | row-gap: var(--spacer-lg);
538 | }
539 |
540 | .settings {
541 | padding: 0!important;
542 | row-gap: 0;
543 | }
544 |
545 | .settings .row {
546 | padding: var(--spacer-lg) !important;
547 | border-bottom: 1px solid var(--color-divider-light);
548 | }
549 |
550 | .last-row {
551 | border: none!important;
552 | }
553 |
554 | .additional-settings .row {
555 | padding: var(--spacer-sm) var(--spacer-lg) !important;
556 | }
557 |
558 | .settings .row .col {
559 | row-gap: 4px;
560 | }
561 |
562 | .settings-header {
563 | display: inline-flex;
564 | column-gap: var(--spacer-xs);
565 | }
566 |
567 | .settings-header span {
568 | font-size: 14px;
569 | font-weight: 600;
570 | color: var(--color-panel-heading);
571 | }
572 |
573 | .slider-wrapper {
574 | padding: var(--spacer-xs) 0 0 0;
575 | }
576 |
577 | .bsr-slider {
578 | border: none!important;
579 | background: var(--color-divider)!important;
580 | }
581 |
582 | .ui-widget-header {
583 | background: var(--color-accent)!important;
584 | }
585 |
586 | .ui-slider-handle {
587 | top: -6px!important;
588 | cursor: pointer!important;
589 | box-shadow: var(--input-shadow);
590 | }
591 |
592 | .ui-state-hover, .ui-state-focus {
593 | border-color: var(--color-panel-heading)!important;
594 | background: var(--color-white)!important;
595 | }
596 |
597 | .tables {
598 | row-gap: var(--spacer-xs);
599 | }
600 |
601 | .import-file {
602 | border-radius: var(--panel-border-radius);
603 | padding: var(--spacer-sm);
604 | border: 1px solid var( --color-divider);
605 | }
606 |
607 | .checkbox {
608 | justify-content: center;
609 | }
610 |
611 | label.replace_guids {
612 | column-gap: var(--spacer-xs);
613 | align-items: center;
614 | display: flex;
615 | }
616 |
617 | label.replace_guids a {
618 | display: inline-flex;
619 | }
620 |
621 | label.replace_guids img {
622 | width: 16px;
623 | margin-top: -2px;
624 | }
625 |
626 | #search_for, #replace_with {
627 | width: 100%;
628 | display: inline-flex;
629 | align-content: center;
630 | line-height: 1;
631 | }
632 |
633 | #profile-name {
634 | padding-left: 80px!important;
635 | }
636 |
637 | .regular-text {
638 | background: var(--color-white)!important;
639 | border: 1px solid var(--color-divider)!important;
640 | box-shadow: var(--input-shadow)!important;
641 | border-radius: var(--panel-border-radius);
642 | height: var(--spacer-xl);
643 | }
644 |
645 | #bsr-table-select {
646 | width: 100% !important;
647 | max-width: 100%;
648 | height: 200px;
649 | max-height: 200px;
650 | padding: var(--spacer-xs)!important;
651 | }
652 |
653 | .description {
654 | color: var(--color-desc-text)!important;
655 | }
656 |
657 | p.submit {
658 | margin: 0;
659 | padding: 0;
660 | }
661 |
662 | .helper-message {
663 | font-size: 14px;
664 | color: var(--color-body-text);
665 | line-height: 1.4em;
666 | padding: 10px 16px;
667 | border-radius: var(--panel-border-radius);
668 | background-color: #fff;
669 | position: absolute;
670 | max-width: 500px;
671 | z-index: 9999;
672 | display: none;
673 | box-shadow: 4px 0px 20px rgba(0,0,0,0.20);
674 | text-align: left;
675 | }
676 |
677 | .helper-message.right:after {
678 | content: '';
679 | border-bottom: 8px solid transparent;
680 | border-right: 8px solid #fff;
681 | border-top: 8px solid transparent;
682 | display: block;
683 | height: 0;
684 | left: -7px;
685 | position: absolute;
686 | top: 11px;
687 | width: 0;
688 | }
689 |
690 | .helper-message.left:before {
691 | content: '';
692 | border-bottom: 8px solid transparent;
693 | border-left: 8px solid #fff;
694 | border-top: 8px solid transparent;
695 | display: block;
696 | height: 0;
697 | right: -7px;
698 | position: absolute;
699 | top: 11px;
700 | width: 0;
701 | }
702 |
703 | .helper-message.bottom:before {
704 | content: '';
705 | border-left: 8px solid transparent;
706 | border-right: 8px solid transparent;
707 | border-bottom: 8px solid #aaa;
708 | border-top: 0;
709 | display: block;
710 | height: 0;
711 | left: 50%;
712 | margin-left: -8px;
713 | position: absolute;
714 | top: -9px;
715 | width: 0;
716 | }
717 |
718 | .helper-message.bottom:after {
719 | content: '';
720 | border-left: 8px solid transparent;
721 | border-right: 8px solid transparent;
722 | border-bottom: 8px solid #fff;
723 | border-top: 0;
724 | display: block;
725 | height: 0;
726 | left: 50%;
727 | margin-left: -8px;
728 | position: absolute;
729 | top: -8px;
730 | width: 0;
731 | }
732 |
733 | /*INPUT STYLING----------------------------*/
734 |
735 | input#submit {
736 | min-height: 40px!important;
737 | }
738 |
739 | label {
740 | font-size: 14px;
741 | }
742 | .input-text {
743 | display: flex;
744 | flex-direction: column;
745 | row-gap: var(--spacer-xs);
746 | }
747 |
748 | input[type="text"] {
749 | padding: 0 var(--spacer-sm)!important;
750 | }
751 |
752 | input[type="text"]:focus, select:focus {
753 | border-color: var(--color-primary) !important;
754 | outline: 0;
755 | box-shadow: 0 0 0 1px var(--color-primary) !important;
756 | }
757 |
758 | input[type="checkbox"] {
759 | margin: 0;
760 | }
761 |
762 | /*checkbox input*/
763 | input[type="checkbox"] {
764 | /* margin: 0 0.5rem; */
765 | width: 18px !important;
766 | height: 18px !important;
767 | box-shadow: none !important;
768 | }
769 |
770 | input[type=checkbox]:checked {
771 | border: none;
772 | background: var(--color-primary);
773 | content: url("data:image/svg+xml,%3Csvg width='6' height='4' viewBox='3 -4 3 14' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M3.95048 6.24692C3.55481 6.64497 2.91278 6.64497 2.5173 6.24692L0.296759 4.01311C-0.0989197 3.61525 -0.0989197 2.96939 0.296759 2.57154C0.692247 2.17349 1.33427 2.17349 1.72995 2.57154L3.05295 3.90226C3.15283 4.00254 3.31495 4.00254 3.41502 3.90226L6.99732 0.298534C7.39281 -0.0995112 8.03483 -0.0995112 8.43051 0.298534C8.62052 0.48968 8.72727 0.749023 8.72727 1.01932C8.72727 1.28961 8.62052 1.54896 8.43051 1.7401L3.95048 6.24692Z' fill='white'/%3E%3C/svg%3E%0A");
774 | border-color: var(--color-primary);
775 | }
776 |
777 | input[type=checkbox]:checked::before {
778 | border: none;
779 | color: #fff;
780 | background-image: url("data:image/svg+xml,%3Csvg width='9' height='7' viewBox='0 0 9 7' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M3.95048 6.24692C3.55481 6.64497 2.91278 6.64497 2.5173 6.24692L0.296759 4.01311C-0.0989197 3.61525 -0.0989197 2.96939 0.296759 2.57154C0.692247 2.17349 1.33427 2.17349 1.72995 2.57154L3.05295 3.90226C3.15283 4.00254 3.31495 4.00254 3.41502 3.90226L6.99732 0.298534C7.39281 -0.0995112 8.03483 -0.0995112 8.43051 0.298534C8.62052 0.48968 8.72727 0.749023 8.72727 1.01932C8.72727 1.28961 8.62052 1.54896 8.43051 1.7401L3.95048 6.24692Z' fill='white'/%3E%3C/svg%3E%0A");
781 | }
782 |
783 | input[type="checkbox"]:focus {
784 | outline: 0.15rem solid rgba(35, 109, 231, .4);
785 | outline-offset: 1px;
786 | box-shadow: none;
787 | }
788 |
789 | input[type="file" i] {
790 | margin-inline-end: 16px!important;
791 | }
792 |
793 | input[type="file" i]::-webkit-file-upload-button {
794 | margin-inline-end: 16px!important;
795 | }
796 |
797 | textarea[readonly] {
798 | width: 100%;
799 | height: 480px;
800 | font-family: Menlo,Monaco,monospace;
801 | font-size: 12px;
802 | margin: 0;
803 | background: var(--color-header);
804 | color: var(--color-white);
805 | padding: var(--spacer-sm);
806 | border-radius: var(--panel-border-radius);
807 | border: none;
808 | box-shadow: var(--input-shadow)
809 | }
810 |
811 | select {
812 | border-radius: var(--panel-border-radius)!important;
813 | border: 1px solid var(--color-divider)!important;
814 | box-shadow: var(--input-shadow)!important;
815 | height: var(--spacer-xl);
816 | }
817 |
818 | .select {
819 | width: 320px;
820 | max-width: 320px;
821 | line-height: 1;
822 | padding: 0 var(--spacer-sm)!important;
823 | }
824 |
825 | select option {
826 | font-size: 13px!important;
827 | }
828 |
829 | .saved-profiles .panel-content {
830 | row-gap: var(--spacer-md)!important;
831 | }
832 |
833 | .profile-select {
834 | align-items: flex-end;
835 | column-gap: var(--spacer-xs);
836 | }
837 |
838 | .license-field {
839 | display: flex;
840 | column-gap: var(--spacer-xs);
841 | }
842 |
843 | #bsr-license-active, #bsr-license-inactive {
844 | display:none;
845 | }
846 |
847 | #wpfooter p {
848 | font-style: italic;
849 | }
850 |
851 | /*BREAKPOINT STYLING----------------------------*/
852 |
853 | @media only screen and (max-width: 800px) {
854 | #bsr_license_key {
855 | width: 100%;
856 | }
857 | .license-field {
858 | width: 100%;
859 | }
860 | }
861 |
862 | @media only screen and (max-width: 640px) {
863 | .search-replace {
864 | flex-direction: column;
865 | row-gap: var(--spacer-md);
866 | }
867 | .profile-select {
868 | flex-direction: column;
869 | row-gap: var(--spacer-sm);
870 | }
871 | .profile-select .input-text, #bsr-profile {
872 | width: 100%!important;
873 | max-width: 100%!important;
874 | }
875 | .license-field {
876 | flex-direction: column;
877 | row-gap: var(--spacer-sm);
878 | }
879 | .license-field input[type="submit"] {
880 | width: max-content;
881 | }
882 | }
883 |
884 | @media only screen and (max-width: 480px) {
885 | .select {
886 | width: 100%!important;
887 | }
888 | }
889 |
890 |
891 | /*SIDEBAR STYLING----------------------------*/
892 |
893 | .upgrade-sidebar {
894 | max-width: 290px;
895 | height: fit-content;
896 | background: linear-gradient(176.44deg, #0F5858 2.92%, #10585C 23.02%, #145469 42.98%, #0D3458 71.92%, #062645 99.66%);
897 | border-radius: var(--panel-border-radius);
898 | }
899 |
900 | .upgrade-sidebar .content {
901 | padding: 0 var(--spacer-md);
902 | }
903 |
904 | .upgrade-sidebar .content h3 {
905 | color: var(--color-white);
906 | font-size: 24px;
907 | margin-top: 16px;
908 | }
909 |
910 | .upgrade-sidebar .content p {
911 | line-height: 1.6;
912 | color: var(--color-white);
913 | font-size: 16px;
914 | }
915 |
916 | .upgrade-sidebar ul {
917 | padding: var(--spacer-md) 0;
918 | display: flex;
919 | flex-direction: column;
920 | row-gap: 16px;
921 | }
922 |
923 | .upgrade-sidebar ul li {
924 | display: flex;
925 | column-gap: var(--spacer-sm);
926 | align-items: flex-start;
927 | list-style: none;
928 | padding-left: 28px;
929 | background: url("data:image/svg+xml,%3Csvg width='19' height='19' viewBox='0 0 19 19' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10.6568 17.1461C15.008 16.3789 17.9133 12.2296 17.1461 7.87846C16.3789 3.5273 12.2296 0.621957 7.87846 1.38919C3.5273 2.15641 0.621957 6.30567 1.38919 10.6568C2.15641 15.008 6.30567 17.9133 10.6568 17.1461ZM14.3711 7.55993L8.43564 13.4954C8.23406 13.697 7.90729 13.697 7.70571 13.4954L4.35087 10.1405C4.14932 9.93899 4.14932 9.61218 4.35087 9.41064L5.08077 8.68073C5.28235 8.47918 5.60916 8.47918 5.81071 8.68073L8.07067 10.9407L12.9113 6.10012C13.1129 5.89854 13.4397 5.89854 13.6412 6.10012L14.3711 6.83002C14.5727 7.03157 14.5727 7.35838 14.3711 7.55993Z' fill='%2324CE87'/%3E%3C/svg%3E%0A") 0 2px no-repeat;
930 | }
931 |
932 | .upgrade-sidebar ul li p {
933 | font-size: 13.5px!important;
934 | opacity: .8;
935 | margin: 0;
936 | }
937 |
938 | .upgrade-offer-text {
939 | text-align: center;
940 | font-weight: bold;
941 | font-style: italic;
942 | font-size: 14.5px!important;
943 | }
944 |
945 | .upgrade-offer-text span {
946 | color: var(--color-accent);
947 | }
948 |
949 | .button-row {
950 | width: 100%;
951 | margin: 0 auto;
952 | padding: var(--spacer-sm) 0 var(--spacer-lg) 0;
953 | text-align: center;
954 | }
955 |
956 | .button-row a {
957 | font-size: 13.5px!important;
958 | font-weight: 600!important;
959 | text-transform: uppercase;
960 | letter-spacing: 2px!important;
961 | border: 0!important;
962 | padding: 0 var(--spacer-lg)!important;
963 | box-shadow: 0 4px 4px 0 rgba(0,0,0,.25);
964 | }
965 |
--------------------------------------------------------------------------------
/assets/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deliciousbrains/better-search-replace/8d4bce24c96f431f5ec8abb4232c0481862c9119/assets/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png
--------------------------------------------------------------------------------
/assets/css/images/ui-bg_diagonals-thick_20_666666_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deliciousbrains/better-search-replace/8d4bce24c96f431f5ec8abb4232c0481862c9119/assets/css/images/ui-bg_diagonals-thick_20_666666_40x40.png
--------------------------------------------------------------------------------
/assets/css/images/ui-bg_flat_10_000000_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deliciousbrains/better-search-replace/8d4bce24c96f431f5ec8abb4232c0481862c9119/assets/css/images/ui-bg_flat_10_000000_40x100.png
--------------------------------------------------------------------------------
/assets/css/images/ui-bg_glass_100_f6f6f6_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deliciousbrains/better-search-replace/8d4bce24c96f431f5ec8abb4232c0481862c9119/assets/css/images/ui-bg_glass_100_f6f6f6_1x400.png
--------------------------------------------------------------------------------
/assets/css/images/ui-bg_glass_100_fdf5ce_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deliciousbrains/better-search-replace/8d4bce24c96f431f5ec8abb4232c0481862c9119/assets/css/images/ui-bg_glass_100_fdf5ce_1x400.png
--------------------------------------------------------------------------------
/assets/css/images/ui-bg_glass_65_ffffff_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deliciousbrains/better-search-replace/8d4bce24c96f431f5ec8abb4232c0481862c9119/assets/css/images/ui-bg_glass_65_ffffff_1x400.png
--------------------------------------------------------------------------------
/assets/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deliciousbrains/better-search-replace/8d4bce24c96f431f5ec8abb4232c0481862c9119/assets/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png
--------------------------------------------------------------------------------
/assets/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deliciousbrains/better-search-replace/8d4bce24c96f431f5ec8abb4232c0481862c9119/assets/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png
--------------------------------------------------------------------------------
/assets/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deliciousbrains/better-search-replace/8d4bce24c96f431f5ec8abb4232c0481862c9119/assets/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png
--------------------------------------------------------------------------------
/assets/css/images/ui-icons_222222_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deliciousbrains/better-search-replace/8d4bce24c96f431f5ec8abb4232c0481862c9119/assets/css/images/ui-icons_222222_256x240.png
--------------------------------------------------------------------------------
/assets/css/images/ui-icons_228ef1_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deliciousbrains/better-search-replace/8d4bce24c96f431f5ec8abb4232c0481862c9119/assets/css/images/ui-icons_228ef1_256x240.png
--------------------------------------------------------------------------------
/assets/css/images/ui-icons_ef8c08_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deliciousbrains/better-search-replace/8d4bce24c96f431f5ec8abb4232c0481862c9119/assets/css/images/ui-icons_ef8c08_256x240.png
--------------------------------------------------------------------------------
/assets/css/images/ui-icons_ffd27a_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deliciousbrains/better-search-replace/8d4bce24c96f431f5ec8abb4232c0481862c9119/assets/css/images/ui-icons_ffd27a_256x240.png
--------------------------------------------------------------------------------
/assets/css/images/ui-icons_ffffff_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deliciousbrains/better-search-replace/8d4bce24c96f431f5ec8abb4232c0481862c9119/assets/css/images/ui-icons_ffffff_256x240.png
--------------------------------------------------------------------------------
/assets/img/bsr-logo-white.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
8 |
9 |
10 |
11 |
12 |
15 |
17 |
18 |
21 |
22 |
--------------------------------------------------------------------------------
/assets/img/phil-gravatar.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deliciousbrains/better-search-replace/8d4bce24c96f431f5ec8abb4232c0481862c9119/assets/img/phil-gravatar.jpeg
--------------------------------------------------------------------------------
/assets/img/sidebar-upgrade.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deliciousbrains/better-search-replace/8d4bce24c96f431f5ec8abb4232c0481862c9119/assets/img/sidebar-upgrade.png
--------------------------------------------------------------------------------
/assets/index.php:
--------------------------------------------------------------------------------
1 | ' + response.message + '
' );
34 | }
35 |
36 | if ( 'done' == response.step ) {
37 |
38 | bsr_update_progress_bar( '100%' );
39 |
40 | // Maybe run another action.
41 | if ( typeof response.next_action != 'undefined' ) {
42 | bsr_update_progress_bar( '0%', 0 );
43 | bsr_process_step( response.next_action, 0, 0, response.bsr_data );
44 | } else {
45 | $('.bsr-processing-wrap').remove();
46 | $('.bsr-disabled').removeClass('bsr-disabled button-disabled' );
47 | window.location = response.url;
48 | }
49 |
50 | } else {
51 | bsr_update_progress_bar( response.percentage );
52 | bsr_process_step( action, response.step, response.page, response.bsr_data );
53 | }
54 |
55 | }
56 | }).fail(function (response) {
57 | $('.bsr-processing-wrap').remove();
58 | $('.bsr-disabled').removeClass('bsr-disabled button-disabled' );
59 | $('#bsr-error-wrap').html( '' + bsr_object_vars.unknown + '
' ).show();
60 | if ( window.console && window.console.log ) {
61 | console.log(response);
62 | }
63 | });
64 |
65 | }
66 |
67 | /**
68 | * Initializes a search/replace.
69 | */
70 | function bsr_search_replace() {
71 |
72 | var search_replace_submit = $( '#bsr-submit' );
73 | var bsr_error_wrap = $( '#bsr-error-wrap' );
74 | search_replace_submit.on( 'click', function( e ) {
75 |
76 | e.preventDefault();
77 |
78 | if ( ! search_replace_submit.hasClass( 'button-disabled' ) ) {
79 |
80 | if ( ! $( '#search_for' ).val() ) {
81 | bsr_error_wrap.html( '' + bsr_object_vars.no_search + '
' ).show();
82 | } else if ( ! $( '#bsr-table-select' ).val() ) {
83 | bsr_error_wrap.html( '' + bsr_object_vars.no_tables + '
' ).show();
84 | } else {
85 | var str = $( '.bsr-action-form' ).serialize();
86 | var data = str.replace(/%5C/g, "#BSR_BACKSLASH#" );
87 |
88 | bsr_error_wrap.html('').hide();
89 | search_replace_submit.addClass( 'bsr-disabled button-disabled' );
90 | $( '#bsr-submit-wrap' ).before('');
91 | $('.bsr-progress-wrap').append( '' + bsr_object_vars.processing + '
' );
92 | bsr_process_step( 'process_search_replace', 0, 0, data );
93 | }
94 |
95 | }
96 |
97 | });
98 |
99 | }
100 |
101 | /**
102 | * Updates the progress bar for AJAX bulk actions.
103 | */
104 | function bsr_update_progress_bar( percentage, speed ) {
105 | if ( typeof speed == 'undefined' ) {
106 | speed = 150;
107 | }
108 | $( '.bsr-progress' ).animate({
109 | width: percentage
110 | }, speed );
111 | }
112 |
113 | /**
114 | * Updates the "Max Page Size" slider.
115 | */
116 | function bsr_update_sliders( percentage ) {
117 | $('#bsr-page-size-slider').slider({
118 | value: bsr_object_vars.page_size,
119 | range: "min",
120 | min: 1000,
121 | max: 50000,
122 | step: 1000,
123 | slide: function( event, ui ) {
124 | $('#bsr-page-size-value').text( ui.value );
125 | $('#bsr_page_size').val( ui.value );
126 | }
127 | });
128 | }
129 |
130 | bsr_init();
131 |
132 | function toggle_tooltip( icon ) {
133 | var icon = $( icon );
134 | var bubble = icon.next();
135 |
136 | // Close any that are already open
137 | $( '.helper-message' ).not( bubble ).hide();
138 |
139 | var position = icon.position();
140 |
141 | if ( icon.parent()[0].nodeName === 'TD' ) {
142 | position = icon.offset();
143 | }
144 |
145 | if ( bubble.hasClass( 'left' ) ) {
146 | bubble.css({
147 | 'left': ( position.left - bubble.width() - icon.width() - 29 ) + 'px',
148 | 'top': ( position.top + icon.height() / 2 - 18 ) + 'px'
149 | })
150 | } else if ( bubble.hasClass( 'bottom' ) ) {
151 | bubble.css( {
152 | 'left': ( ( position.left - bubble.width() / 2 ) - 5 ) + 'px',
153 | 'top': ( position.top + icon.height() + 19 ) + 'px'
154 | } );
155 | } else {
156 | bubble.css( {
157 | 'left': ( position.left + icon.width() + 19 ) + 'px',
158 | 'top': ( position.top + icon.height() / 2 - 18 ) + 'px'
159 | } );
160 | }
161 |
162 | bubble.toggle();
163 | }
164 |
165 | $('body').on('thickbox:iframe:loaded', function(){
166 | var $iframeBody = $( '#TB_window iframe' ).contents().find( 'body' );
167 |
168 | $iframeBody.on( 'mouseover', '.tooltip', function( e ) {
169 | e.preventDefault();
170 | $iframeBody.find( '.helper-message' ).hide();
171 | toggle_tooltip( this );
172 | e.stopPropagation();
173 | });
174 |
175 | $iframeBody.on( 'mouseleave', 'td', function( e ) {
176 | $iframeBody.find( '.helper-message' ).hide();
177 | });
178 | });
179 |
180 | $( 'body' ).on( 'mouseover', '.tooltip', function( e ) {
181 | toggle_tooltip( this );
182 | } );
183 |
184 | $( 'body' ).on( 'mouseleave', '.tooltip', function( e ) {
185 | $( '.helper-message' ).hide();
186 | } );
187 |
188 | $( '.notice.inline' )
189 | .appendTo('.bsr-notice-container' )
190 | .css( 'display', 'block' );
191 |
192 | setTimeout(function() {
193 | const $settings_saved_notice = $( '#setting-error-settings_updated' );
194 | const $bsr_notices = $( '.bsr-updated' );
195 |
196 | if ( $settings_saved_notice.length || $bsr_notices.length ) {
197 | $( '
' ).prependTo( '.inside' );
198 | $settings_saved_notice.prependTo( '.bsr-inner-notice-container' ).css( 'display', 'block' );
199 | $bsr_notices.prependTo( '.bsr-inner-notice-container' ).css( 'display', 'block' );
200 | }
201 |
202 | $( '.bsr-inner-notice-container .notice-dismiss' ).on( 'click', function ( e ) {
203 | if ( ! $bsr_notices.length ) {
204 | $( '.bsr-inner-notice-container' ).remove();
205 | }
206 | });
207 | }, 75);
208 |
209 |
210 |
211 | })( jQuery );
212 |
--------------------------------------------------------------------------------
/assets/svg/icon-arrow.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/icon-checkmark.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/assets/svg/icon-help.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/assets/svg/icon-upgrade.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/assets/svg/logo-bsr.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/assets/svg/mdb-birds.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/better-search-replace.php:
--------------------------------------------------------------------------------
1 | .
38 | */
39 |
40 | // If this file was called directly, abort.
41 | if ( ! defined( 'WPINC' ) ) {
42 | die;
43 | }
44 |
45 | if ( ! function_exists( 'run_better_search_replace' ) ) {
46 | // Defines the path to the main plugin file.
47 | define( 'BSR_FILE', __FILE__ );
48 |
49 | // Defines the path to be used for includes.
50 | define( 'BSR_PATH', plugin_dir_path( BSR_FILE ) );
51 |
52 | // Defines the URL to the plugin.
53 | define( 'BSR_URL', plugin_dir_url( BSR_FILE ) );
54 |
55 | // Defines the current version of the plugin.
56 | define( 'BSR_VERSION', '1.4.11-dev' );
57 |
58 | // Defines the name of the plugin.
59 | define( 'BSR_NAME', 'Better Search Replace' );
60 |
61 | /**
62 | * Begins execution of the plugin.
63 | *
64 | * Since everything within the plugin is registered via hooks,
65 | * then kicking off the plugin from this point in the file does
66 | * not affect the page life cycle.
67 | *
68 | * @since 1.0.0
69 | */
70 | function run_better_search_replace() {
71 | if ( bsr_enabled_for_user() ) {
72 | /**
73 | * The core plugin class that is used to define internationalization,
74 | * dashboard-specific hooks, and public-facing site hooks.
75 | */
76 | require BSR_PATH . 'includes/class-bsr-main.php';
77 | $plugin = new Better_Search_Replace();
78 | $plugin->run();
79 | }
80 | }
81 |
82 | add_action( 'after_setup_theme', 'run_better_search_replace' );
83 | }
84 |
85 | if ( ! function_exists( 'bsr_enabled_for_user' ) ) {
86 | /**
87 | * Is the current user allowed to use BSR?
88 | *
89 | * @return bool
90 | */
91 | function bsr_enabled_for_user() {
92 | // Allows for overriding the capability required to run the plugin.
93 | $cap = apply_filters( 'bsr_capability', 'manage_options' );
94 |
95 | return current_user_can( $cap );
96 | }
97 | }
98 |
99 | if ( file_exists( BSR_PATH . 'ext/bsr-ext-functions.php' ) ) {
100 | require_once BSR_PATH . 'ext/bsr-ext-functions.php';
101 | }
102 |
--------------------------------------------------------------------------------
/build-cfg/better-search-replace/config.php:
--------------------------------------------------------------------------------
1 | svn/trunk/better-search-replace.php.tmp" );
17 | system( 'mv svn/trunk/better-search-replace.php.tmp svn/trunk/better-search-replace.php' );
18 | system( 'svn stat svn/ | grep \'^\?\' | awk \'{print $2}\' | xargs -I x svn add x@' );
19 | system( 'svn stat svn/ | grep \'^\!\' | awk \'{print $2}\' | xargs -I x svn rm --force x@' );
20 | system( "svn cp svn/trunk svn/tags/$version" );
21 | system( 'svn stat svn/' );
22 |
23 | echo 'Commit to WP.org? (Y/n)? ';
24 | if ( 'Y' == strtoupper( trim( fgets( STDIN ) ) ) ) {
25 | system( "svn ci --username deliciousbrains svn/ -m 'Deploy version $version'" );
26 | }
27 |
28 | system( 'rm -fR svn' ); // All done
29 | }
30 |
--------------------------------------------------------------------------------
/build-cfg/better-search-replace/version-check.php:
--------------------------------------------------------------------------------
1 | array(
4 | '@Version:\s+(.*)\n@' => 'header',
5 | "/define\(\s*'BSR_VERSION',\s*'([^']+)'\s*\);/" => 'constant',
6 | ),
7 | );
--------------------------------------------------------------------------------
/build-cfg/build-plugin.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | function usage() {
4 | echo "Usage: $0 [ slug1 slug2 ... ]"
5 | exit 1
6 | }
7 |
8 | SCRIPT_ARGS="$@"
9 | PROJECT_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
10 | PLUGIN_SRC_PATH="$PROJECT_ROOT"
11 | PLUGIN_BUILDS_PATH="$PROJECT_ROOT/builds"
12 | PLUGIN_BUILD_CONFIG_PATH="$PROJECT_ROOT/build-cfg"
13 | PUBLISH=""
14 | if [[ $* == *--publish* ]]
15 | then
16 | PUBLISH="-p"
17 | fi
18 |
19 | function echog() {
20 | echo "$(tput setaf 2)$1$(tput sgr 0)"
21 | }
22 | function echor() {
23 | echo "$(tput setaf 1)$1$(tput sgr 0)"
24 | }
25 |
26 | function build_plugin() {
27 | PLUGIN_DIR="$PLUGIN_BUILD_CONFIG_PATH/$PLUGIN"
28 |
29 | if [[ -d "$PLUGIN_DIR" && ! -L "$PLUGIN_DIR" ]]; then
30 | if [ "utils" != "$PLUGIN" ] && [ "common" != "$PLUGIN" ];
31 | then
32 | VERSION=$(php -f "$PLUGIN_BUILD_CONFIG_PATH/utils/get_plugin_version.php" "$PROJECT_ROOT" $PLUGIN)
33 | ZIP_NAME=$(php -f "$PLUGIN_BUILD_CONFIG_PATH/utils/get_plugin_zip_name.php" "$PROJECT_ROOT" $PLUGIN)
34 | BUILD_ZIP="$PLUGIN_BUILDS_PATH/$ZIP_NAME-$VERSION.zip";
35 |
36 | if [ -f "$BUILD_ZIP" ]
37 | then
38 | rm "$BUILD_ZIP"
39 | fi
40 |
41 | echog "Building $PLUGIN v$VERSION..."
42 | cd "$PLUGIN_BUILD_CONFIG_PATH/$PLUGIN/"
43 | "$PLUGIN_BUILDS_PATH/plugin-build" "$VERSION" "$PUBLISH"
44 | echog "Plugin built: $BUILD_ZIP"
45 | echo "--------------------------"
46 | fi
47 | else
48 | usage
49 | fi
50 | }
51 |
52 | cd "$PROJECT_ROOT";
53 |
54 | if [[ $SCRIPT_ARGS == *--pro-version* ]]
55 | then
56 | echo $(php -f "$PLUGIN_BUILD_CONFIG_PATH/utils/get_plugin_version.php" "$PROJECT_ROOT" wp-offload-ses)
57 | exit;
58 | fi
59 |
60 | if [ -z "${SCRIPT_ARGS}" ]
61 | then
62 | echog "Clearing previously built plugins..."
63 | rm -rf "$PLUGIN_BUILDS_PATH"
64 | fi
65 |
66 | if [ ! -d "$PLUGIN_BUILDS_PATH" ]
67 | then
68 | mkdir -p "$PLUGIN_BUILDS_PATH"
69 | fi
70 |
71 | if [ ! -f "$PLUGIN_BUILDS_PATH/plugin-build" -o ! -x "$PLUGIN_BUILDS_PATH/plugin-build" ]
72 | then
73 | echog "Downloading plugin-build script..."
74 | curl -sSL https://raw.githubusercontent.com/deliciousbrains/wp-plugin-build/582fdeb3f6d19ae0b1f2bd0da9b48f45c131ac34/plugin-build -o "$PLUGIN_BUILDS_PATH/plugin-build"
75 | chmod +x "$PLUGIN_BUILDS_PATH/plugin-build"
76 | fi
77 |
78 | echog "Building plugins..."
79 | if [ -z "${SCRIPT_ARGS}" ]
80 | then
81 | for PLUGIN_DIR in "$PLUGIN_BUILD_CONFIG_PATH"/*/
82 | do
83 | PLUGIN=$(basename "$PLUGIN_DIR");
84 |
85 | build_plugin
86 | done
87 | else
88 | for PLUGIN in ${SCRIPT_ARGS}
89 | do
90 | build_plugin
91 | done
92 | fi
--------------------------------------------------------------------------------
/build-cfg/utils/create-json.php:
--------------------------------------------------------------------------------
1 | get_readme_meta( $readme ),
19 | $this->get_php_file_meta( $plugin )
20 | );
21 |
22 | return json_encode( $plugin_info, JSON_PRETTY_PRINT );
23 | }
24 |
25 | /**
26 | * Get the meta data from the readme.txt file.
27 | *
28 | * @param string $readme The contents of the readme.txt file.
29 | *
30 | * @return array
31 | */
32 | public function get_readme_meta( $readme ) {
33 | $readme_headers = array(
34 | 'contributors' => 'contributors',
35 | 'tags' => 'Tags',
36 | 'requires_at_least' => 'Requires at least',
37 | 'tested_up_to' => 'Tested up to',
38 | 'stable_tag' => 'Stable tag',
39 | );
40 |
41 | $meta = $this->get_file_meta( $readme, $readme_headers );
42 |
43 | $section_names = array(
44 | 'description' => 'Description',
45 | 'changelog' => 'Changelog',
46 | 'faq' => 'Frequently Asked Questions',
47 | );
48 |
49 | $sections = $this->get_readme_sections( $readme, $section_names );
50 | if ( ! empty( $sections ) ) {
51 | $meta['sections'] = $sections;
52 | }
53 |
54 | return $meta;
55 | }
56 |
57 | /**
58 | * Get the meta data from the main plugin file.
59 | *
60 | * @param string $plugin The contents of the main plugin file.
61 | *
62 | * @return array
63 | */
64 | public function get_php_file_meta( $plugin ) {
65 | $plugin_headers = array(
66 | 'name' => 'Plugin Name',
67 | 'pluginURI' => 'Plugin URI',
68 | 'version' => 'Version',
69 | 'description' => 'Description',
70 | 'author' => 'Author',
71 | 'authorURI' => 'Author URI',
72 | 'textDomain' => 'Text Domain',
73 | 'domainPath' => 'Domain Path',
74 | 'network' => 'Network',
75 | );
76 |
77 | return $this->get_file_meta( $plugin, $plugin_headers );
78 | }
79 |
80 | /**
81 | * Retrieve metadata from a file.
82 | *
83 | * Searches for metadata in the first 8kiB of a file, such as a plugin or theme.
84 | * Each piece of metadata must be on its own line. Fields can not span multiple
85 | * lines, the value will get cut at the end of the first line.
86 | *
87 | *
88 | * @param string $content File contents.
89 | * @param array $headers List of headers, in the format array('HeaderKey' => 'Header Name').
90 | *
91 | * @return array Array of file headers in `HeaderKey => Header Value` format.
92 | */
93 | protected function get_file_meta( $content, $headers ) {
94 | // Make sure we catch CR-only line endings.
95 | $content = str_replace( "\r", "\n", $content );
96 | $all_headers = array();
97 |
98 | foreach ( $headers as $field => $regex ) {
99 | $pattern = '/^[ \t\/*#@]*' . preg_quote($regex, '/' ) . ':(.*)$/mi';
100 |
101 | if ( preg_match( $pattern , $content, $match ) && $match[1] ) {
102 | $all_headers[ $field ] = $this->clean_header_comment( $match[1] );
103 | } else {
104 | $all_headers[ $field ] = '';
105 | }
106 | }
107 |
108 | return $all_headers;
109 | }
110 |
111 | protected function get_readme_sections( $str, $defined_sections ) {
112 | $parts = preg_split(
113 | '/^\s*==\s*(.+?)\s*==/m',
114 | $str,
115 | -1,
116 | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY
117 | );
118 |
119 | $sections = array();
120 | for ( $i=1; $i <= count( $parts ); $i +=2 ) {
121 | $title = $this->sanitize_text( $parts[$i-1] );
122 | if ( ! in_array( $title, $defined_sections ) ) {
123 | continue;
124 | }
125 |
126 | $content = $this->sanitize_text( $parts[ $i ] );
127 | $key = array_flip( $defined_sections )[ $title ];
128 | $sections[ $key ] = $content;
129 | }
130 |
131 | return $sections;
132 | }
133 |
134 | /**
135 | * Strip close comment and close php tags from file headers used by WP.
136 | *
137 | * @see https://core.trac.wordpress.org/ticket/8497
138 | *
139 | * @param string $str Header comment to clean up.
140 | *
141 | * @return string
142 | */
143 | protected function clean_header_comment( $str ) {
144 | return trim( preg_replace( "/\s*(?:\*\/|\?>).*/", '', $str ) );
145 | }
146 |
147 | /**
148 | * Non fancy text sanitization.
149 | *
150 | * @param string $text
151 | *
152 | * @return string
153 | */
154 | private function sanitize_text( $text ) {
155 | $text = trim($text);
156 |
157 | return $text;
158 | }
159 |
160 | }
161 |
162 | $plugin_meta = new Plugin_Meta();
163 | echo $plugin_meta->get_plugin_meta( $argv[1], $argv[2] );
164 |
--------------------------------------------------------------------------------
/build-cfg/utils/get_plugin_version.php:
--------------------------------------------------------------------------------
1 | $regexes ) {
17 | $file = "$src_dir/$file";
18 |
19 | if ( ! file_exists( $file ) ) {
20 | $messages .= "Whoa! Couldn't find $file\n";
21 | continue;
22 | }
23 |
24 | $file_content = file_get_contents( $file );
25 |
26 | if ( ! $file_content ) {
27 | $messages .= "Whoa! Could not read contents of $file\n";
28 | continue;
29 | }
30 |
31 | foreach ( $regexes as $regex => $context ) {
32 | if ( ! preg_match( $regex, $file_content, $matches ) ) {
33 | $messages .= "Whoa! Couldn't find $context version number in $file\n";
34 | continue;
35 | }
36 |
37 | if ( isset( $matches[1] ) ) {
38 | return $matches[1];
39 | }
40 | }
41 | }
42 | }
43 |
44 | echo $messages;
45 |
46 | return false;
47 | }
--------------------------------------------------------------------------------
/build-cfg/utils/get_plugin_zip_name.php:
--------------------------------------------------------------------------------
1 | 'better-search-replace',
10 | 'plugin_basename' => plugin_basename( BSR_FILE ),
11 | );
12 |
13 | require_once BSR_PATH . 'ext/class-bsr-plugin-updater.php';
14 | new DeliciousBrains\Better_Search_Replace\BSR_Plugin_Updater( $properties );
15 | }
16 |
17 | add_action( 'admin_init', 'bsr_check_for_upgrades' );
18 | }
19 |
--------------------------------------------------------------------------------
/ext/class-bsr-plugin-updater.php:
--------------------------------------------------------------------------------
1 | api_url = 'https://wpe-plugin-updates.wpengine.com/';
59 |
60 | $this->cache_time = time() + HOUR_IN_SECONDS * 5;
61 |
62 | $this->properties = $this->get_full_plugin_properties( $properties, $this->api_url );
63 |
64 | if ( ! $this->properties ) {
65 | return;
66 | }
67 |
68 | $this->register();
69 | }
70 |
71 | /**
72 | * Get the full plugin properties, including the directory name, version, basename, and add a transient name.
73 | *
74 | * @param array $properties These properties are passed in when instantiating to identify the plugin and it's update location.
75 | * @param string $api_url The URL where the api is located.
76 | *
77 | * @return array|null
78 | */
79 | public function get_full_plugin_properties( $properties, $api_url ) {
80 | $plugins = \get_plugins();
81 |
82 | // Scan through all plugins installed and find the one which matches this one in question.
83 | foreach ( $plugins as $plugin_basename => $plugin_data ) {
84 | // Match using the passed-in plugin's basename.
85 | if ( $plugin_basename === $properties['plugin_basename'] ) {
86 | // Add the values we need to the properties.
87 | $properties['plugin_dirname'] = dirname( $plugin_basename );
88 | $properties['plugin_version'] = $plugin_data['Version'];
89 | $properties['plugin_update_transient_name'] = 'wpesu-plugin-' . sanitize_title( $properties['plugin_dirname'] );
90 | $properties['plugin_update_transient_exp_name'] = 'wpesu-plugin-' . sanitize_title( $properties['plugin_dirname'] ) . '-expiry';
91 | $properties['plugin_manifest_url'] = trailingslashit( $api_url ) . trailingslashit( $properties['plugin_slug'] ) . 'info.json';
92 |
93 | return $properties;
94 | }
95 | }
96 |
97 | // No matching plugin was found installed.
98 | return null;
99 | }
100 |
101 | /**
102 | * Register hooks.
103 | *
104 | * @return void
105 | */
106 | public function register() {
107 | add_filter( 'plugins_api', array( $this, 'filter_plugin_update_info' ), 20, 3 );
108 | add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'filter_plugin_update_transient' ) );
109 | }
110 |
111 | /**
112 | * Filter the plugin update transient to take over update notifications.
113 | *
114 | * @param ?object $transient_value The value of the `site_transient_update_plugins` transient.
115 | *
116 | * @handles site_transient_update_plugins
117 | * @return object|null
118 | */
119 | public function filter_plugin_update_transient( $transient_value ) {
120 | // No update object exists. Return early.
121 | if ( empty( $transient_value ) ) {
122 | return $transient_value;
123 | }
124 |
125 | $result = $this->fetch_plugin_info();
126 |
127 | if ( false === $result ) {
128 | return $transient_value;
129 | }
130 |
131 | $res = $this->parse_plugin_info( $result );
132 |
133 | if ( version_compare( $this->properties['plugin_version'], $result->version, '<' ) ) {
134 | $transient_value->response[ $res->plugin ] = $res;
135 | $transient_value->checked[ $res->plugin ] = $result->version;
136 | } else {
137 | $transient_value->no_update[ $res->plugin ] = $res;
138 | }
139 |
140 | return $transient_value;
141 | }
142 |
143 | /**
144 | * Filters the plugin update information.
145 | *
146 | * @param object $res The response to be modified for the plugin in question.
147 | * @param string $action The action in question.
148 | * @param object $args The arguments for the plugin in question.
149 | *
150 | * @handles plugins_api
151 | * @return object
152 | */
153 | public function filter_plugin_update_info( $res, $action, $args ) {
154 | // Do nothing if this is not about getting plugin information.
155 | if ( 'plugin_information' !== $action ) {
156 | return $res;
157 | }
158 |
159 | // Do nothing if it is not our plugin.
160 | if ( $this->properties['plugin_dirname'] !== $args->slug ) {
161 | return $res;
162 | }
163 |
164 | $result = $this->fetch_plugin_info();
165 |
166 | // Do nothing if we don't get the correct response from the server.
167 | if ( false === $result ) {
168 | return $res;
169 | }
170 |
171 | return $this->parse_plugin_info( $result );
172 | }
173 |
174 | /**
175 | * Fetches the plugin update object from the WP Product Info API.
176 | *
177 | * @return object|false
178 | */
179 | private function fetch_plugin_info() {
180 | // Fetch cache first.
181 | $expiry = get_option( $this->properties['plugin_update_transient_exp_name'], 0 );
182 | $response = get_option( $this->properties['plugin_update_transient_name'] );
183 |
184 | if ( empty( $expiry ) || time() > $expiry || empty( $response ) ) {
185 | $response = wp_remote_get(
186 | $this->properties['plugin_manifest_url'],
187 | array(
188 | 'timeout' => 10,
189 | 'headers' => array(
190 | 'Accept' => 'application/json',
191 | ),
192 | )
193 | );
194 |
195 | if (
196 | is_wp_error( $response ) ||
197 | 200 !== wp_remote_retrieve_response_code( $response ) ||
198 | empty( wp_remote_retrieve_body( $response ) )
199 | ) {
200 | return false;
201 | }
202 |
203 | $response = wp_remote_retrieve_body( $response );
204 |
205 | // Cache the response.
206 | update_option( $this->properties['plugin_update_transient_exp_name'], $this->cache_time, false );
207 | update_option( $this->properties['plugin_update_transient_name'], $response, false );
208 | }
209 |
210 | $decoded_response = json_decode( $response );
211 |
212 | if ( json_last_error() !== JSON_ERROR_NONE ) {
213 | return false;
214 | }
215 |
216 | return $decoded_response;
217 | }
218 |
219 | /**
220 | * Parses the product info response into an object that WordPress would be able to understand.
221 | *
222 | * @param object $response The response object.
223 | *
224 | * @return stdClass
225 | */
226 | private function parse_plugin_info( $response ) {
227 | global $wp_version;
228 |
229 | $res = new stdClass();
230 | $res->name = $response->name;
231 | $res->slug = $response->slug;
232 | $res->version = $response->version;
233 | $res->requires = $response->requires;
234 | $res->download_link = $response->download_link;
235 | $res->trunk = $response->download_link;
236 | $res->new_version = $response->version;
237 | $res->plugin = $this->properties['plugin_basename'];
238 | $res->package = $response->download_link;
239 |
240 | // Plugin information modal and core update table use a strict version comparison, which is weird.
241 | // If we're genuinely not compatible with the point release, use our WP tested up to version.
242 | // otherwise use exact same version as WP to avoid false positive.
243 | $res->tested = 1 === version_compare( substr( $wp_version, 0, 3 ), $response->tested )
244 | ? $response->tested
245 | : $wp_version;
246 |
247 | $res->sections = array(
248 | 'description' => $response->sections->description,
249 | 'changelog' => $response->sections->changelog,
250 | );
251 |
252 | return $res;
253 | }
254 | }
255 |
--------------------------------------------------------------------------------
/includes/class-bsr-admin.php:
--------------------------------------------------------------------------------
1 | better_search_replace = $better_search_replace;
48 | $this->version = $version;
49 | }
50 |
51 | /**
52 | * Register any CSS and JS used by the plugin.
53 | * @since 1.0.0
54 | * @access public
55 | * @param string $hook Used for determining which page(s) to load our scripts.
56 | */
57 | public function enqueue_scripts( $hook ) {
58 | if ( 'tools_page_better-search-replace' === $hook ) {
59 | $min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
60 |
61 | wp_enqueue_style( 'better-search-replace', BSR_URL . "assets/css/better-search-replace$min.css", array(), $this->version, 'all' );
62 | wp_enqueue_style( 'jquery-style', BSR_URL . 'assets/css/jquery-ui.min.css', array(), $this->version, 'all' );
63 | wp_enqueue_script( 'jquery-ui-slider' );
64 | wp_enqueue_script( 'better-search-replace', BSR_URL . "assets/js/better-search-replace$min.js", array( 'jquery' ), $this->version, true );
65 | wp_enqueue_style( 'thickbox' );
66 | wp_enqueue_script( 'thickbox' );
67 |
68 | wp_localize_script( 'better-search-replace', 'bsr_object_vars', array(
69 | 'page_size' => get_option( 'bsr_page_size' ) ? absint( get_option( 'bsr_page_size' ) ) : 20000,
70 | 'endpoint' => BSR_AJAX::get_endpoint(),
71 | 'ajax_nonce' => wp_create_nonce( 'bsr_ajax_nonce' ),
72 | 'no_search' => __( 'No search string was defined, please enter a URL or string to search for.', 'better-search-replace' ),
73 | 'no_tables' => __( 'Please select the tables that you want to update.', 'better-search-replace' ),
74 | 'unknown' => __( 'An error occurred processing your request. Try decreasing the "Max Page Size", or contact support.', 'better-search-replace' ),
75 | 'processing' => __( 'Processing...', 'better-search-replace' )
76 | ) );
77 | }
78 | }
79 |
80 | /**
81 | * Register any menu pages used by the plugin.
82 | * @since 1.0.0
83 | * @access public
84 | */
85 | public function bsr_menu_pages() {
86 | $cap = apply_filters( 'bsr_capability', 'manage_options' );
87 | add_submenu_page( 'tools.php', __( 'Better Search Replace', 'better-search-replace' ), __( 'Better Search Replace', 'better-search-replace' ), $cap, 'better-search-replace', array( $this, 'bsr_menu_pages_callback' ) );
88 | }
89 |
90 | /**
91 | * The callback for creating a new submenu page under the "Tools" menu.
92 | * @access public
93 | */
94 | public function bsr_menu_pages_callback() {
95 | require_once BSR_PATH . 'includes/class-bsr-templates-helper.php';
96 | require_once BSR_PATH . 'templates/bsr-dashboard.php';
97 | }
98 |
99 | /**
100 | * Renders the result or error onto the better-search-replace admin page.
101 | */
102 | public static function render_result() {
103 | // Trying to show results?
104 | if ( ! isset( $_GET['result'] ) ) {
105 | return;
106 | }
107 |
108 | $result = get_transient( 'bsr_results' );
109 |
110 | // Have results with required fields set with correctly typed data?
111 | if (
112 | empty( $result ) ||
113 | ! isset( $result['tables'] ) ||
114 | ! is_int( $result['tables'] ) ||
115 | ! isset( $result['change'] ) ||
116 | ! is_int( $result['change'] ) ||
117 | ! isset( $result['updates'] ) ||
118 | ! is_int( $result['updates'] )
119 | ) {
120 | return;
121 | }
122 |
123 | if ( isset( $result['dry_run'] ) && $result['dry_run'] === 'on' ) {
124 | $msg = sprintf(
125 | __(
126 | 'DRY RUN: %1$d tables were searched, %2$d cells were found that need to be updated, and %3$d changes were made.
Click here for more details, or use the form below to run the search/replace.
',
127 | 'better-search-replace'
128 | ),
129 | $result['tables'],
130 | $result['change'],
131 | $result['updates'],
132 | get_admin_url() . 'admin-post.php?action=bsr_view_details&TB_iframe=true&width=800&height=500'
133 | );
134 | } else {
135 | $msg = sprintf(
136 | __(
137 | 'During the search/replace, %1$d tables were searched, with %2$d cells changed in %3$d updates.
Click here for more details.
',
138 | 'better-search-replace'
139 | ),
140 | $result['tables'],
141 | $result['change'],
142 | $result['updates'],
143 | get_admin_url() . 'admin-post.php?action=bsr_view_details&TB_iframe=true&width=800&height=500'
144 | );
145 | }
146 |
147 | echo '' . $msg . '
';
148 | }
149 |
150 | /**
151 | * Prefills the given value on the search/replace page (dry run, live run, from profile).
152 | * @access public
153 | * @param string $value The value to check for.
154 | * @param string $type The type of the value we're filling.
155 | */
156 | public static function prefill_value( $value, $type = 'text' ) {
157 |
158 | // Grab the correct data to prefill.
159 | if ( isset( $_GET['result'] ) && get_transient( 'bsr_results' ) ) {
160 | $values = get_transient( 'bsr_results' );
161 | } else {
162 | $values = array();
163 | }
164 |
165 | // Prefill the value.
166 | if ( isset( $values[$value] ) ) {
167 |
168 | if ( 'checkbox' === $type && 'on' === $values[$value] ) {
169 | echo 'checked';
170 | } else {
171 | echo str_replace( '#BSR_BACKSLASH#', '\\', esc_attr( htmlentities( $values[$value] ) ) );
172 | }
173 |
174 | }
175 |
176 | }
177 |
178 | /**
179 | * Loads the tables available to run a search replace, prefilling if already
180 | * selected the tables.
181 | * @access public
182 | */
183 | public static function load_tables() {
184 |
185 | // Get the tables and their sizes.
186 | $tables = BSR_DB::get_tables();
187 | $sizes = BSR_DB::get_sizes();
188 |
189 | echo '';
190 |
191 | foreach ( $tables as $table ) {
192 |
193 | // Try to get the size for this specific table.
194 | $table_size = isset( $sizes[$table] ) ? $sizes[$table] : '';
195 |
196 | if ( isset( $_GET['result'] ) && get_transient( 'bsr_results' ) ) {
197 |
198 | $result = get_transient( 'bsr_results' );
199 |
200 | if ( isset( $result['table_reports'][$table] ) ) {
201 | echo "$table $table_size ";
202 | } else {
203 | echo "$table $table_size ";
204 | }
205 |
206 | } else {
207 | echo "$table $table_size ";
208 | }
209 |
210 | }
211 |
212 | echo ' ';
213 |
214 | }
215 |
216 | /**
217 | * Loads the result details (via Thickbox).
218 | * @access public
219 | */
220 | public function load_details() {
221 |
222 | if ( get_transient( 'bsr_results' ) ) {
223 | $results = get_transient( 'bsr_results' );
224 | $min = ( defined( 'SCRIPT_DEBUG' ) && true === SCRIPT_DEBUG ) ? '' : '.min';
225 | $bsr_styles = BSR_URL . 'assets/css/better-search-replace.css?v=' . BSR_VERSION;
226 |
227 | ?>
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 | $report ) {
239 | $time = $report['end'] - $report['start'];
240 |
241 | if ( $report['change'] != 0 ) {
242 | $report['change'] = '' . esc_html( $report['change'] ). ' ';
243 |
244 | $upgrade_link = sprintf(
245 | __( 'UPGRADE to view details on the exact changes that will be made.', 'better-search-replace'),
246 | 'https://deliciousbrains.com/better-search-replace/upgrade/?utm_source=insideplugin&utm_medium=web&utm_content=tooltip&utm_campaign=bsr-to-migrate'
247 | );
248 |
249 | $report['change'] .= '' . $upgrade_link . ' ';
250 | }
251 |
252 | if ( $report['updates'] != 0 ) {
253 | $report['updates'] = '' . esc_html( $report['updates'] ) . ' ';
254 | }
255 |
256 | echo '' . esc_html( $table_name ) . ' ' . $report['change'] . ' ' . $report['updates'] . ' ' . round( $time, 3 ) . __( ' seconds', 'better-search-replace' ) . ' ';
257 | }
258 | ?>
259 |
260 |
261 |
262 | ' . __( 'Upgrade to Pro', 'better-search-replace' ) . '' )
304 | );
305 | }
306 |
307 | return $links;
308 | }
309 |
310 | }
311 |
--------------------------------------------------------------------------------
/includes/class-bsr-ajax.php:
--------------------------------------------------------------------------------
1 | add_ajax_actions();
26 | }
27 |
28 | /**
29 | * Gets our custom endpoint.
30 | * @access public
31 | * @return string
32 | */
33 | public static function get_endpoint() {
34 | return esc_url_raw( get_admin_url() . 'tools.php?page=better-search-replace&bsr-ajax=' );
35 | }
36 |
37 | /**
38 | * Set BSR AJAX constant and headers.
39 | * @access public
40 | */
41 | public function define_ajax() {
42 |
43 | if ( isset( $_GET['bsr-ajax'] ) && ! empty( $_GET['bsr-ajax'] ) ) {
44 |
45 | // Define the WordPress "DOING_AJAX" constant.
46 | if ( ! defined( 'DOING_AJAX' ) ) {
47 | define( 'DOING_AJAX', true );
48 | }
49 |
50 | // Prevent notices from breaking AJAX functionality.
51 | if ( ! WP_DEBUG || ( WP_DEBUG && ! WP_DEBUG_DISPLAY ) ) {
52 | @ini_set( 'display_errors', 0 );
53 | }
54 |
55 | // Send the headers.
56 | send_origin_headers();
57 | @header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) );
58 | @header( 'X-Robots-Tag: noindex' );
59 | send_nosniff_header();
60 | nocache_headers();
61 |
62 | }
63 |
64 | }
65 |
66 | /**
67 | * Check if we're doing AJAX and fire the related action.
68 | * @access public
69 | */
70 | public function do_bsr_ajax() {
71 | global $wp_query;
72 |
73 | if ( isset( $_GET['bsr-ajax'] ) && ! empty( $_GET['bsr-ajax'] ) ) {
74 | $wp_query->set( 'bsr-ajax', sanitize_text_field( $_GET['bsr-ajax'] ) );
75 | }
76 |
77 | if ( $action = $wp_query->get( 'bsr-ajax' ) ) {
78 | do_action( 'bsr_ajax_' . sanitize_text_field( $action ) );
79 | die();
80 | }
81 | }
82 |
83 | /**
84 | * Adds any AJAX-related actions.
85 | * @access public
86 | */
87 | public function add_ajax_actions() {
88 | $actions = array(
89 | 'process_search_replace',
90 | );
91 |
92 | foreach ( $actions as $action ) {
93 | add_action( 'bsr_ajax_' . $action, array( $this, $action ) );
94 | }
95 | }
96 |
97 | /**
98 | * Processes the search/replace form submitted by the user.
99 | * @access public
100 | */
101 | public function process_search_replace() {
102 | // Bail if not authorized.
103 | if ( ! BSR_Utils::check_admin_referer( 'bsr_ajax_nonce', 'bsr_ajax_nonce' ) ) {
104 | return;
105 | }
106 |
107 | // Initialize the DB class.
108 | $db = new BSR_DB();
109 | $step = isset( $_REQUEST['bsr_step' ] ) ? absint( $_REQUEST['bsr_step'] ) : 0;
110 | $page = isset( $_REQUEST['bsr_page'] ) ? absint( $_REQUEST['bsr_page'] ) : 0;
111 |
112 | // Any operations that should only be performed at the beginning.
113 | if ( $step === 0 && $page === 0 ) {
114 | $args = array();
115 | parse_str( $_POST['bsr_data'], $args );
116 |
117 | // Build the arguments for this run.
118 | if ( ! isset( $args['select_tables'] ) || ! is_array( $args['select_tables'] ) ) {
119 | $args['select_tables'] = array();
120 | }
121 |
122 | $args = array(
123 | 'select_tables' => array_map( 'trim', $args['select_tables'] ),
124 | 'case_insensitive' => isset( $args['case_insensitive'] ) ? $args['case_insensitive'] : 'off',
125 | 'replace_guids' => isset( $args['replace_guids'] ) ? $args['replace_guids'] : 'off',
126 | 'dry_run' => isset( $args['dry_run'] ) ? $args['dry_run'] : 'off',
127 | 'search_for' => isset( $args['search_for'] ) ? stripslashes( $args['search_for'] ) : '',
128 | 'replace_with' => isset( $args['replace_with'] ) ? stripslashes( $args['replace_with'] ) : '',
129 | 'completed_pages' => isset( $args['completed_pages'] ) ? absint( $args['completed_pages'] ) : 0,
130 | );
131 |
132 | $args['total_pages'] = isset( $args['total_pages'] ) ? absint( $args['total_pages'] ) : $db->get_total_pages( $args['select_tables'] );
133 |
134 | // Clear the results of the last run.
135 | delete_transient( 'bsr_results' );
136 | delete_option( 'bsr_data' );
137 | } else {
138 | $args = get_option( 'bsr_data' );
139 | }
140 |
141 | // Start processing data.
142 | if ( isset( $args['select_tables'][$step] ) ) {
143 |
144 | $result = $db->srdb( $args['select_tables'][$step], $page, $args );
145 | $this->append_report( $args['select_tables'][$step], $result['table_report'], $args );
146 |
147 | if ( false === $result['table_complete'] ) {
148 | $page++;
149 | } else {
150 | $step++;
151 | $page = 0;
152 | }
153 |
154 | // Check if isset() again as the step may have changed since last check.
155 | if ( isset( $args['select_tables'][$step] ) ) {
156 | $msg_tbl = esc_html( $args['select_tables'][$step] );
157 |
158 | $message = sprintf(
159 | __( 'Processing table %d of %d: %s', 'better-search-replace' ),
160 | $step + 1,
161 | count( $args['select_tables'] ),
162 | $msg_tbl
163 | );
164 | }
165 |
166 | $args['completed_pages']++;
167 | $percentage = $args['completed_pages'] / $args['total_pages'] * 100 . '%';
168 |
169 | } else {
170 | $db->maybe_update_site_url();
171 | $step = 'done';
172 | $percentage = '100%';
173 | }
174 |
175 | update_option( 'bsr_data', $args );
176 |
177 | // Store results in an array.
178 | $result = array(
179 | 'step' => $step,
180 | 'page' => $page,
181 | 'percentage' => $percentage,
182 | 'url' => get_admin_url() . 'tools.php?page=better-search-replace&tab=bsr_search_replace&result=true',
183 | 'bsr_data' => build_query( $args )
184 | );
185 |
186 | if ( isset( $message ) ) {
187 | $result['message'] = $message;
188 | }
189 |
190 | // Send output as JSON for processing via AJAX.
191 | echo json_encode( $result );
192 | exit;
193 |
194 | }
195 |
196 | /**
197 | * Helper function for assembling the BSR Results.
198 | * @access public
199 | * @param string $table The name of the table to append to.
200 | * @param array $report The report for that table.
201 | * @param array $args An array of arguements used for this run.
202 | * @return boolean
203 | */
204 | public function append_report( $table, $report, $args ) {
205 |
206 | // Bail if not authorized.
207 | if ( ! BSR_Utils::check_admin_referer( 'bsr_ajax_nonce', 'bsr_ajax_nonce' ) ) {
208 | return false;
209 | }
210 |
211 | // Retrieve the existing transient.
212 | $results = get_transient( 'bsr_results' ) ? get_transient( 'bsr_results') : array();
213 |
214 | // Grab any values from the run args.
215 | $results['search_for'] = isset( $args['search_for'] ) ? $args['search_for'] : '';
216 | $results['replace_with'] = isset( $args['replace_with'] ) ? $args['replace_with'] : '';
217 | $results['dry_run'] = isset( $args['dry_run'] ) ? $args['dry_run'] : 'off';
218 | $results['case_insensitive'] = isset( $args['case_insensitive'] ) ? $args['case_insensitive'] : 'off';
219 | $results['replace_guids'] = isset( $args['replace_guids'] ) ? $args['replace_guids'] : 'off';
220 |
221 | // Sum the values of the new and existing reports.
222 | $results['change'] = isset( $results['change'] ) ? $results['change'] + $report['change'] : $report['change'];
223 | $results['updates'] = isset( $results['updates'] ) ? $results['updates'] + $report['updates'] : $report['updates'];
224 |
225 | // Append the table report, or create a new one if necessary.
226 | if ( isset( $results['table_reports'] ) && isset( $results['table_reports'][$table] ) ) {
227 | $results['table_reports'][$table]['change'] = $results['table_reports'][$table]['change'] + $report['change'];
228 | $results['table_reports'][$table]['updates'] = $results['table_reports'][$table]['updates'] + $report['updates'];
229 | $results['table_reports'][$table]['end'] = $report['end'];
230 | } else {
231 | $results['table_reports'][$table] = $report;
232 | }
233 |
234 | // Count the number of tables.
235 | $results['tables'] = count( $results['table_reports'] );
236 |
237 | // Update the transient.
238 | if ( ! set_transient( 'bsr_results', $results, DAY_IN_SECONDS ) ) {
239 | return false;
240 | }
241 |
242 | return true;
243 |
244 | }
245 |
246 | }
247 |
248 | $bsr_ajax = new BSR_AJAX;
249 | $bsr_ajax->init();
250 |
--------------------------------------------------------------------------------
/includes/class-bsr-compatibility.php:
--------------------------------------------------------------------------------
1 | prefix ) . "\n";
35 | $return .= 'WP_DEBUG: ' . ( defined( 'WP_DEBUG' ) ? WP_DEBUG ? 'Enabled' : 'Disabled' : 'Not set' ) . "\n";
36 | $return .= 'Memory Limit: ' . WP_MEMORY_LIMIT . "\n";
37 |
38 | // Plugin Configuration
39 | $return .= "\n" . '-- Better Search Replace Configuration' . "\n\n";
40 | $return .= 'Plugin Version: ' . BSR_VERSION . "\n";
41 | $db = new BSR_DB();
42 | $return .= 'Max Page Size: ' . $db->get_page_size() . "\n";
43 |
44 | // Server Configuration
45 | $return .= "\n" . '-- Server Configuration' . "\n\n";
46 | $os = self::get_os();
47 | $return .= 'Operating System: ' . $os['name'] . "\n";
48 | $return .= 'PHP Version: ' . PHP_VERSION . "\n";
49 | $return .= 'MySQL Version: ' . $wpdb->db_version() . "\n";
50 |
51 | $return .= 'Server Software: ' . $_SERVER['SERVER_SOFTWARE'] . "\n";
52 |
53 | // PHP configs... now we're getting to the important stuff
54 | $return .= "\n" . '-- PHP Configuration' . "\n\n";
55 | $return .= 'Memory Limit: ' . ini_get( 'memory_limit' ) . "\n";
56 | $return .= 'Post Max Size: ' . ini_get( 'post_max_size' ) . "\n";
57 | $return .= 'Upload Max Filesize: ' . ini_get( 'upload_max_filesize' ) . "\n";
58 | $return .= 'Time Limit: ' . ini_get( 'max_execution_time' ) . "\n";
59 | $return .= 'Max Input Vars: ' . ini_get( 'max_input_vars' ) . "\n";
60 | $return .= 'Display Errors: ' . ( ini_get( 'display_errors' ) ? 'On (' . ini_get( 'display_errors' ) . ')' : 'N/A' ) . "\n";
61 |
62 | // WordPress active plugins
63 | $return .= "\n" . '-- WordPress Active Plugins' . "\n\n";
64 | $plugins = get_plugins();
65 | $active_plugins = get_option( 'active_plugins', array() );
66 | foreach( $plugins as $plugin_path => $plugin ) {
67 | if( !in_array( $plugin_path, $active_plugins ) )
68 | continue;
69 | $return .= $plugin['Name'] . ': ' . $plugin['Version'] . "\n";
70 | }
71 |
72 | // WordPress inactive plugins
73 | $return .= "\n" . '-- WordPress Inactive Plugins' . "\n\n";
74 | foreach( $plugins as $plugin_path => $plugin ) {
75 | if( in_array( $plugin_path, $active_plugins ) )
76 | continue;
77 | $return .= $plugin['Name'] . ': ' . $plugin['Version'] . "\n";
78 | }
79 |
80 | if( is_multisite() ) {
81 | // WordPress Multisite active plugins
82 | $return .= "\n" . '-- Network Active Plugins' . "\n\n";
83 | $plugins = wp_get_active_network_plugins();
84 | $active_plugins = get_site_option( 'active_sitewide_plugins', array() );
85 | foreach( $plugins as $plugin_path ) {
86 | $plugin_base = plugin_basename( $plugin_path );
87 | if( !array_key_exists( $plugin_base, $active_plugins ) )
88 | continue;
89 | $plugin = get_plugin_data( $plugin_path );
90 | $return .= $plugin['Name'] . ': ' . $plugin['Version'] . "\n";
91 | }
92 | }
93 |
94 | $return .= "\n" . '### End System Info ###';
95 | return $return;
96 | }
97 |
98 | /**
99 | * Determines the current operating system.
100 | * @access public
101 | * @return array
102 | */
103 | public static function get_os() {
104 | $os = array();
105 | $uname = php_uname( 's' );
106 | $os['code'] = strtoupper( substr( $uname, 0, 3 ) );
107 | $os['name'] = $uname;
108 | return $os;
109 | }
110 |
111 | }
112 |
--------------------------------------------------------------------------------
/includes/class-bsr-db.php:
--------------------------------------------------------------------------------
1 | wpdb = $wpdb;
42 |
43 | $this->page_size = $this->get_page_size();
44 | }
45 |
46 | /**
47 | * Returns an array of tables in the database.
48 | * @access public
49 | * @return array
50 | */
51 | public static function get_tables() {
52 | global $wpdb;
53 |
54 | if ( function_exists( 'is_multisite' ) && is_multisite() ) {
55 |
56 | if ( is_main_site() ) {
57 | $tables = $wpdb->get_col( 'SHOW TABLES' );
58 | } else {
59 | $blog_id = get_current_blog_id();
60 | $tables = $wpdb->get_col( "SHOW TABLES LIKE '" . $wpdb->base_prefix . absint( $blog_id ) . "\_%'" );
61 | }
62 |
63 | } else {
64 | $tables = $wpdb->get_col( 'SHOW TABLES' );
65 | }
66 |
67 | return $tables;
68 | }
69 |
70 | /**
71 | * Returns an array containing the size of each database table.
72 | * @access public
73 | * @return array
74 | */
75 | public static function get_sizes() {
76 | global $wpdb;
77 |
78 | $sizes = array();
79 | $tables = $wpdb->get_results( 'SHOW TABLE STATUS', ARRAY_A );
80 |
81 | if ( is_array( $tables ) && ! empty( $tables ) ) {
82 |
83 | foreach ( $tables as $table ) {
84 | $size = round( $table['Data_length'] / 1024 / 1024, 2 );
85 | $sizes[$table['Name']] = sprintf( __( '(%s MB)', 'better-search-replace' ), $size );
86 | }
87 |
88 | }
89 |
90 | return $sizes;
91 | }
92 |
93 | /**
94 | * Returns the current page size.
95 | * @access public
96 | * @return int
97 | */
98 | public function get_page_size() {
99 | $page_size = get_option( 'bsr_page_size' ) ? get_option( 'bsr_page_size' ) : 20000;
100 | return absint( $page_size );
101 | }
102 |
103 | /**
104 | * Returns the number of pages in a table.
105 | * @access public
106 | * @return int
107 | */
108 | public function get_pages_in_table( $table ) {
109 | if ( false === $this->table_exists( $table ) ) {
110 | return 0;
111 | }
112 |
113 | $table = esc_sql( $table );
114 | $rows = $this->wpdb->get_var( "SELECT COUNT(*) FROM `$table`" );
115 | $pages = ceil( $rows / $this->page_size );
116 |
117 | return absint( $pages );
118 | }
119 |
120 | /**
121 | * Gets the total number of pages in the DB.
122 | * @access public
123 | * @return int
124 | */
125 | public function get_total_pages( $tables ) {
126 | $total_pages = 0;
127 |
128 | foreach ( $tables as $table ) {
129 |
130 | // Get the number of rows & pages in the table.
131 | $pages = $this->get_pages_in_table( $table );
132 |
133 | // Always include 1 page in case we have to create schemas, etc.
134 | if ( $pages == 0 ) {
135 | $pages = 1;
136 | }
137 |
138 | $total_pages += $pages;
139 | }
140 |
141 | return absint( $total_pages );
142 | }
143 |
144 | /**
145 | * Gets the columns in a table.
146 | * @access public
147 | * @param string $table The table to check.
148 | * @return array
149 | */
150 | public function get_columns( $table ) {
151 | $primary_key = null;
152 | $columns = array();
153 |
154 | if ( false === $this->table_exists( $table ) ) {
155 | return array( $primary_key, $columns );
156 | }
157 |
158 | $fields = $this->wpdb->get_results( 'DESCRIBE ' . $table );
159 |
160 | if ( is_array( $fields ) ) {
161 | foreach ( $fields as $column ) {
162 | $columns[] = $column->Field;
163 | if ( $column->Key == 'PRI' ) {
164 | $primary_key = $column->Field;
165 | }
166 | }
167 | }
168 |
169 | return array( $primary_key, $columns );
170 | }
171 |
172 | /**
173 | * Adapated from interconnect/it's search/replace script.
174 | *
175 | * Modified to use WordPress wpdb functions instead of PHP's native mysql/pdo functions,
176 | * and to be compatible with batch processing via AJAX.
177 | *
178 | * @link https://interconnectit.com/products/search-and-replace-for-wordpress-databases/
179 | *
180 | * @access public
181 | * @param string $table The table to run the replacement on.
182 | * @param int $page The page/block to begin the query on.
183 | * @param array $args An associative array containing arguements for this run.
184 | * @return array
185 | */
186 | public function srdb( $table, $page, $args ) {
187 |
188 | // Load up the default settings for this chunk.
189 | $table = esc_sql( $table );
190 | $current_page = absint( $page );
191 | $pages = $this->get_pages_in_table( $table );
192 | $done = false;
193 |
194 | $args['search_for'] = str_replace( '#BSR_BACKSLASH#', '\\', $args['search_for'] );
195 | $args['replace_with'] = str_replace( '#BSR_BACKSLASH#', '\\', $args['replace_with'] );
196 |
197 | $table_report = array(
198 | 'change' => 0,
199 | 'updates' => 0,
200 | 'start' => microtime( true ),
201 | 'end' => microtime( true ),
202 | 'errors' => array(),
203 | 'skipped' => false
204 | );
205 |
206 | // Get a list of columns in this table.
207 | list( $primary_key, $columns ) = $this->get_columns( $table );
208 |
209 | // Bail out early if there isn't a primary key.
210 | if ( null === $primary_key ) {
211 | $table_report['skipped'] = true;
212 | return array( 'table_complete' => true, 'table_report' => $table_report );
213 | }
214 |
215 | $current_row = 0;
216 | $start = $page * $this->page_size;
217 | $end = $this->page_size;
218 |
219 | // Grab the content of the table.
220 | $data = $this->wpdb->get_results( "SELECT * FROM `$table` LIMIT $start, $end", ARRAY_A );
221 |
222 | // Loop through the data.
223 | foreach ( $data as $row ) {
224 | $current_row++;
225 | $update_sql = array();
226 | $where_sql = array();
227 | $upd = false;
228 |
229 | foreach( $columns as $column ) {
230 |
231 | $data_to_fix = $row[ $column ];
232 |
233 | if ( $column == $primary_key ) {
234 | $where_sql[] = $column . ' = "' . $this->mysql_escape_mimic( $data_to_fix ) . '"';
235 | continue;
236 | }
237 |
238 | // Skip GUIDs by default.
239 | if ( 'on' !== $args['replace_guids'] && 'guid' == $column ) {
240 | continue;
241 | }
242 |
243 | if ( $this->wpdb->options === $table ) {
244 |
245 | // Skip any BSR options as they may contain the search field.
246 | if ( isset( $should_skip ) && true === $should_skip ) {
247 | $should_skip = false;
248 | continue;
249 | }
250 |
251 | // If the Site URL needs to be updated, let's do that last.
252 | if ( isset( $update_later ) && true === $update_later ) {
253 | $update_later = false;
254 | $edited_data = $this->recursive_unserialize_replace( $args['search_for'], $args['replace_with'], $data_to_fix, false, $args['case_insensitive'] );
255 |
256 | if ( $edited_data != $data_to_fix ) {
257 | $table_report['change']++;
258 | $table_report['updates']++;
259 | update_option( 'bsr_update_site_url', $edited_data );
260 | continue;
261 | }
262 | }
263 |
264 | if ( '_transient_bsr_results' === $data_to_fix || 'bsr_profiles' === $data_to_fix || 'bsr_update_site_url' === $data_to_fix || 'bsr_data' === $data_to_fix ) {
265 | $should_skip = true;
266 | }
267 |
268 | if ( 'siteurl' === $data_to_fix && $args['dry_run'] !== 'on' ) {
269 | $update_later = true;
270 | }
271 |
272 | }
273 |
274 | // Run a search replace on the data that'll respect the serialisation.
275 | $edited_data = $this->recursive_unserialize_replace( $args['search_for'], $args['replace_with'], $data_to_fix, false, $args['case_insensitive'] );
276 |
277 | // Something was changed
278 | if ( $edited_data != $data_to_fix ) {
279 | $update_sql[] = $column . ' = "' . $this->mysql_escape_mimic( $edited_data ) . '"';
280 | $upd = true;
281 | $table_report['change']++;
282 | }
283 |
284 | }
285 |
286 | // Determine what to do with updates.
287 | if ( $args['dry_run'] === 'on' ) {
288 | // Don't do anything if a dry run
289 | } elseif ( $upd && ! empty( $where_sql ) ) {
290 | // If there are changes to make, run the query.
291 | $sql = 'UPDATE ' . $table . ' SET ' . implode( ', ', $update_sql ) . ' WHERE ' . implode( ' AND ', array_filter( $where_sql ) );
292 | $result = $this->wpdb->query( $sql );
293 |
294 | if ( ! $result ) {
295 | $table_report['errors'][] = sprintf( __( 'Error updating row: %d.', 'better-search-replace' ), $current_row );
296 | } else {
297 | $table_report['updates']++;
298 | }
299 |
300 | }
301 |
302 | } // end row loop
303 |
304 | if ( $current_page >= $pages - 1 ) {
305 | $done = true;
306 | }
307 |
308 | // Flush the results and return the report.
309 | $table_report['end'] = microtime( true );
310 | $this->wpdb->flush();
311 | return array( 'table_complete' => $done, 'table_report' => $table_report );
312 | }
313 |
314 | /**
315 | * Adapated from interconnect/it's search/replace script.
316 | *
317 | * @link https://interconnectit.com/products/search-and-replace-for-wordpress-databases/
318 | *
319 | * Take a serialised array and unserialise it replacing elements as needed and
320 | * unserialising any subordinate arrays and performing the replace on those too.
321 | *
322 | * @access private
323 | * @param string $from String we're looking to replace.
324 | * @param string $to What we want it to be replaced with
325 | * @param array $data Used to pass any subordinate arrays back to in.
326 | * @param boolean $serialised Does the array passed via $data need serialising.
327 | * @param sting|boolean $case_insensitive Set to 'on' if we should ignore case, false otherwise.
328 | *
329 | * @return string|array The original array with all elements replaced as needed.
330 | */
331 | public function recursive_unserialize_replace( $from = '', $to = '', $data = '', $serialised = false, $case_insensitive = false ) {
332 | try {
333 | // Exit early if $data is a string but has no search matches.
334 | if ( is_string( $data ) ) {
335 | $has_match = $case_insensitive ? false !== stripos( $data, $from ) : false !== strpos( $data, $from );
336 | if ( ! $has_match ) {
337 | return $data;
338 | }
339 | }
340 |
341 | if ( is_string( $data ) && ! is_serialized_string( $data ) && ( $unserialized = $this->unserialize( $data ) ) !== false ) {
342 | $data = $this->recursive_unserialize_replace( $from, $to, $unserialized, true, $case_insensitive );
343 | }
344 |
345 | elseif ( is_array( $data ) ) {
346 | $_tmp = array( );
347 | foreach ( $data as $key => $value ) {
348 | $_tmp[ $key ] = $this->recursive_unserialize_replace( $from, $to, $value, false, $case_insensitive );
349 | }
350 |
351 | $data = $_tmp;
352 | unset( $_tmp );
353 | }
354 |
355 | // Submitted by Tina Matter
356 | elseif ( 'object' == gettype( $data ) ) {
357 | if($this->is_object_cloneable($data)) {
358 | $_tmp = clone $data;
359 | $props = get_object_vars( $data );
360 | foreach ( $props as $key => $value ) {
361 | // Integer properties are crazy and the best thing we can do is to just ignore them.
362 | // see http://stackoverflow.com/a/10333200
363 | if ( is_int( $key ) ) {
364 | continue;
365 | }
366 |
367 | // Skip any representation of a protected property
368 | // https://github.com/deliciousbrains/better-search-replace/issues/71#issuecomment-1369195244
369 | if ( is_string( $key ) && 1 === preg_match( "/^(\\\\0).+/im", preg_quote( $key ) ) ) {
370 | continue;
371 | }
372 |
373 | $_tmp->$key = $this->recursive_unserialize_replace( $from, $to, $value, false, $case_insensitive );
374 | }
375 |
376 | $data = $_tmp;
377 | unset( $_tmp );
378 | }
379 | }
380 |
381 | elseif ( is_serialized_string( $data ) ) {
382 | $unserialized = $this->unserialize( $data );
383 |
384 | if ( $unserialized !== false ) {
385 | $data = $this->recursive_unserialize_replace( $from, $to, $unserialized, true, $case_insensitive );
386 | }
387 | }
388 |
389 | else {
390 | if ( is_string( $data ) ) {
391 | $data = $this->str_replace( $from, $to, $data, $case_insensitive );
392 | }
393 | }
394 |
395 | if ( $serialised ) {
396 | return serialize( $data );
397 | }
398 |
399 | } catch( Exception $error ) {
400 |
401 | }
402 |
403 | return $data;
404 | }
405 |
406 | /**
407 | * Updates the Site URL if necessary.
408 | * @access public
409 | * @return boolean
410 | */
411 | public function maybe_update_site_url() {
412 | $option = get_option( 'bsr_update_site_url' );
413 |
414 | if ( $option ) {
415 | update_option( 'siteurl', $option );
416 | delete_option( 'bsr_update_site_url' );
417 | return true;
418 | }
419 |
420 | return false;
421 | }
422 |
423 | /**
424 | * Mimics the mysql_real_escape_string function. Adapted from a post by 'feedr' on php.net.
425 | * @link http://php.net/manual/en/function.mysql-real-escape-string.php#101248
426 | * @access public
427 | * @param string $input The string to escape.
428 | * @return string
429 | */
430 | public function mysql_escape_mimic( $input ) {
431 | if ( is_array( $input ) ) {
432 | return array_map( __METHOD__, $input );
433 | }
434 | if ( ! empty( $input ) && is_string( $input ) ) {
435 | return str_replace( array( '\\', "\0", "\n", "\r", "'", '"', "\x1a" ), array( '\\\\', '\\0', '\\n', '\\r', "\\'", '\\"', '\\Z' ), $input );
436 | }
437 |
438 | return $input;
439 | }
440 |
441 | /**
442 | * Return unserialized object or array
443 | *
444 | * @param string $serialized_string Serialized string.
445 | * @param string $method The name of the caller method.
446 | *
447 | * @return mixed, false on failure
448 | */
449 | public static function unserialize( $serialized_string ) {
450 | if ( ! is_serialized( $serialized_string ) ) {
451 | return false;
452 | }
453 |
454 | $serialized_string = trim( $serialized_string );
455 |
456 | if ( PHP_VERSION_ID >= 70000 ) {
457 | $unserialized_string = @unserialize( $serialized_string, array('allowed_classes' => false ) );
458 | } else {
459 | $unserialized_string = @BSR\Brumann\Polyfill\Unserialize::unserialize( $serialized_string, array( 'allowed_classes' => false ) );
460 | }
461 |
462 | return $unserialized_string;
463 | }
464 |
465 | /**
466 | * Wrapper for str_replace
467 | *
468 | * @param string $from
469 | * @param string $to
470 | * @param string $data
471 | * @param string|bool $case_insensitive
472 | *
473 | * @return string
474 | */
475 | public function str_replace( $from, $to, $data, $case_insensitive = false ) {
476 | if ( 'on' === $case_insensitive ) {
477 | $data = str_ireplace( $from, $to, $data );
478 | } else {
479 | $data = str_replace( $from, $to, $data );
480 | }
481 |
482 | return $data;
483 | }
484 |
485 | /**
486 | * Checks whether a table exists in DB.
487 | *
488 | * @param $table
489 | *
490 | * @return bool
491 | */
492 | private function table_exists( $table ) {
493 | return in_array( $table, $this->get_tables() );
494 | }
495 |
496 | /**
497 | * Check if a given object can be cloned.
498 | *
499 | * @param object $object
500 | *
501 | * @return bool
502 | */
503 | private function is_object_cloneable( $object ) {
504 | return ( new \ReflectionClass( get_class( $object ) ) )->isCloneable();
505 | }
506 | }
507 |
--------------------------------------------------------------------------------
/includes/class-bsr-i18n.php:
--------------------------------------------------------------------------------
1 | domain,
37 | false,
38 | dirname( dirname( plugin_basename( __FILE__ ) ) ) . '/languages/'
39 | );
40 |
41 | }
42 |
43 | /**
44 | * Set the domain equal to that of the specified domain.
45 | *
46 | * @since 1.0.0
47 | * @param string $domain The domain that represents the locale of this plugin.
48 | */
49 | public function set_domain( $domain ) {
50 | $this->domain = $domain;
51 | $this->load_plugin_textdomain();
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/includes/class-bsr-loader.php:
--------------------------------------------------------------------------------
1 | actions = array();
54 | $this->filters = array();
55 |
56 | }
57 |
58 | /**
59 | * Add a new action to the collection to be registered with WordPress.
60 | *
61 | * @since 1.0.0
62 | * @var string $hook The name of the WordPress action that is being registered.
63 | * @var object $component A reference to the instance of the object on which the action is defined.
64 | * @var string $callback The name of the function definition on the $component.
65 | * @var int Optional $priority The priority at which the function should be fired.
66 | * @var int Optional $accepted_args The number of arguments that should be passed to the $callback.
67 | */
68 | public function add_action( $hook, $component, $callback, $priority = 10, $accepted_args = 1 ) {
69 | $this->actions = $this->add( $this->actions, $hook, $component, $callback, $priority, $accepted_args );
70 | }
71 |
72 | /**
73 | * Add a new filter to the collection to be registered with WordPress.
74 | *
75 | * @since 1.0.0
76 | * @var string $hook The name of the WordPress filter that is being registered.
77 | * @var object $component A reference to the instance of the object on which the filter is defined.
78 | * @var string $callback The name of the function definition on the $component.
79 | * @var int Optional $priority The priority at which the function should be fired.
80 | * @var int Optional $accepted_args The number of arguments that should be passed to the $callback.
81 | */
82 | public function add_filter( $hook, $component, $callback, $priority = 10, $accepted_args = 1 ) {
83 | $this->filters = $this->add( $this->filters, $hook, $component, $callback, $priority, $accepted_args );
84 | }
85 |
86 | /**
87 | * A utility function that is used to register the actions and hooks into a single
88 | * collection.
89 | *
90 | * @since 1.0.0
91 | * @access private
92 | * @var array $hooks The collection of hooks that is being registered (that is, actions or filters).
93 | * @var string $hook The name of the WordPress filter that is being registered.
94 | * @var object $component A reference to the instance of the object on which the filter is defined.
95 | * @var string $callback The name of the function definition on the $component.
96 | * @var int Optional $priority The priority at which the function should be fired.
97 | * @var int Optional $accepted_args The number of arguments that should be passed to the $callback.
98 | * @return type The collection of actions and filters registered with WordPress.
99 | */
100 | private function add( $hooks, $hook, $component, $callback, $priority, $accepted_args ) {
101 |
102 | $hooks[] = array(
103 | 'hook' => $hook,
104 | 'component' => $component,
105 | 'callback' => $callback,
106 | 'priority' => $priority,
107 | 'accepted_args' => $accepted_args
108 | );
109 |
110 | return $hooks;
111 |
112 | }
113 |
114 | /**
115 | * Register the filters and actions with WordPress.
116 | *
117 | * @since 1.0.0
118 | */
119 | public function run() {
120 |
121 | foreach ( $this->filters as $hook ) {
122 | add_filter( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] );
123 | }
124 |
125 | foreach ( $this->actions as $hook ) {
126 | add_action( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['accepted_args'] );
127 | }
128 |
129 | }
130 |
131 | }
132 |
--------------------------------------------------------------------------------
/includes/class-bsr-main.php:
--------------------------------------------------------------------------------
1 | plugin_name = 'better-search-replace';
61 | $this->version = BSR_VERSION;
62 | $this->load_dependencies();
63 | $this->set_locale();
64 | $this->define_admin_hooks();
65 | }
66 |
67 | /**
68 | * Load the required dependencies for this plugin.
69 | *
70 | * Create an instance of the loader which will be used to register the hooks
71 | * with WordPress.
72 | *
73 | * @since 1.0
74 | * @access private
75 | */
76 | private function load_dependencies() {
77 | require_once BSR_PATH . 'includes/class-bsr-loader.php';
78 | require_once BSR_PATH . 'includes/class-bsr-i18n.php';
79 | require_once BSR_PATH . 'includes/class-bsr-admin.php';
80 | require_once BSR_PATH . 'includes/class-bsr-ajax.php';
81 | require_once BSR_PATH . 'includes/class-bsr-db.php';
82 | require_once BSR_PATH . 'includes/class-bsr-compatibility.php';
83 | require_once BSR_PATH . 'includes/class-bsr-plugin-footer.php';
84 | require_once BSR_PATH . 'includes/class-bsr-utils.php';
85 |
86 | if ( PHP_VERSION_ID < 70000 ) {
87 | require_once BSR_PATH . 'vendor/brumann/polyfill-unserialize/src/Unserialize.php';
88 | require_once BSR_PATH . 'vendor/brumann/polyfill-unserialize/src/DisallowedClassesSubstitutor.php';
89 | }
90 |
91 | $this->loader = new BSR_Loader();
92 | }
93 |
94 | /**
95 | * Define the locale for this plugin for internationalization.
96 | *
97 | * Uses the BSR_i18n class in order to set the domain and to register the hook
98 | * with WordPress.
99 | *
100 | * @since 1.0
101 | * @access private
102 | */
103 | private function set_locale() {
104 | $plugin_i18n = new BSR_i18n();
105 | $plugin_i18n->set_domain( $this->get_plugin_name() );
106 | }
107 |
108 | /**
109 | * Register all of the hooks related to the dashboard functionality
110 | * of the plugin.
111 | *
112 | * @since 1.0
113 | * @access private
114 | */
115 | private function define_admin_hooks() {
116 |
117 | // Initialize the admin class.
118 | $plugin_admin = new BSR_Admin( $this->get_plugin_name(), $this->get_version() );
119 | $plugin_footer = new BSR_Plugin_Footer();
120 |
121 | /// Register the admin pages and scripts.
122 | $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' );
123 | $this->loader->add_action( 'admin_menu', $plugin_admin, 'bsr_menu_pages' );
124 |
125 | // Other admin actions.
126 | $this->loader->add_action( 'admin_init', $plugin_admin, 'register_option' );
127 | $this->loader->add_action( 'admin_post_bsr_view_details', $plugin_admin, 'load_details' );
128 | $this->loader->add_action( 'admin_post_bsr_download_sysinfo', $plugin_admin, 'download_sysinfo' );
129 | $this->loader->add_action( 'plugin_row_meta', $plugin_admin, 'meta_upgrade_link', 10, 2 );
130 |
131 | // Footer Actions
132 | $this->loader->add_filter( 'update_footer', $plugin_footer, 'update_footer', 20);
133 | $this->loader->add_filter( 'admin_footer_text', $plugin_footer, 'admin_footer_text', 20);
134 | }
135 |
136 | /**
137 | * Run the loader to execute all of the hooks with WordPress.
138 | *
139 | * @since 1.0
140 | */
141 | public function run() {
142 | $this->loader->run();
143 | }
144 |
145 | /**
146 | * The name of the plugin used to uniquely identify it within the context of
147 | * WordPress and to define internationalization functionality.
148 | *
149 | * @since 1.0
150 | * @return string The name of the plugin.
151 | */
152 | public function get_plugin_name() {
153 | return $this->plugin_name;
154 | }
155 |
156 | /**
157 | * The reference to the class that orchestrates the hooks with the plugin.
158 | *
159 | * @since 1.0
160 | * @return Better_Search_Replace_Loader Orchestrates the hooks of the plugin.
161 | */
162 | public function get_loader() {
163 | return $this->loader;
164 | }
165 |
166 | /**
167 | * Retrieve the version number of the plugin.
168 | *
169 | * @since 1.0
170 | * @return string The version number of the plugin.
171 | */
172 | public function get_version() {
173 | return $this->version;
174 | }
175 |
176 | }
177 |
--------------------------------------------------------------------------------
/includes/class-bsr-plugin-footer.php:
--------------------------------------------------------------------------------
1 | 'bsr_free',
32 | 'utm_medium' => 'insideplugin',
33 | 'utm_campaign' => 'plugin_footer',
34 | 'utm_content' => 'footer_colophon'
35 | ]
36 | ),
37 | BSR_NAME
38 | );
39 | $wpe_link = BSR_Utils::external_link(
40 | BSR_Utils::wpe_url(
41 | '',
42 | [
43 | 'utm_source' => 'bsr_plugin',
44 | 'utm_content' => 'bsr_free_plugin_footer_text'
45 | ]
46 | ),
47 | 'WP Engine'
48 | );
49 | return sprintf(
50 | /* translators: %1$s is a link to BSR's website, and %2$s is a link to WP Engine's website. */
51 | __( '%1$s is developed and maintained by %2$s.', 'better-search-replace' ),
52 | $product_link,
53 | $wpe_link
54 | );
55 | }
56 |
57 | /**
58 | * Filter update footer text for BSR pages
59 | *
60 | * @param string $content
61 | * @return string
62 | * @handles update_footer
63 | **/
64 | public function update_footer( $content ) {
65 | if ( ! BSR_Utils::is_bsr_screen() ) {
66 | return $content;
67 | }
68 | $utm_params = [
69 | 'utm_source' => 'bsr_free',
70 | 'utm_campaign' => 'plugin_footer',
71 | 'utm_content' => 'footer_navigation'
72 | ];
73 |
74 | $links[] = BSR_Utils::external_link(
75 | BSR_Utils::bsr_url(
76 | '/docs/',
77 | $utm_params
78 | ),
79 | __( 'Documentation', 'better-search-replace' )
80 | );
81 |
82 | $links[] = '' . __( 'Support', 'better-search-replace' ) . ' ';
83 |
84 | $links[] = BSR_Utils::external_link(
85 | BSR_Utils::bsr_url(
86 | '/feedback/',
87 | $utm_params
88 | ),
89 | __( 'Feedback', 'better-search-replace' )
90 | );
91 | if ( defined( 'BSR_NAME' ) && defined( 'BSR_VERSION' ) ) {
92 | $links[] = BSR_NAME . ' ' . BSR_VERSION;
93 | }
94 |
95 | return join( ' ∙ ', $links );
96 | }
97 | }
--------------------------------------------------------------------------------
/includes/class-bsr-templates-helper.php:
--------------------------------------------------------------------------------
1 | %s', esc_url( $url ), esc_html( $text ) );
30 | }
31 |
32 | /**
33 | * Generate Better Search Replace site URL with correct UTM tags.
34 | *
35 | * @param string $path
36 | * @param array $args
37 | * @param string $hash
38 | *
39 | * @return string
40 | */
41 | public static function bsr_url( $path, $args = array(), $hash = '' ) {
42 | $args = wp_parse_args(
43 | $args,
44 | array( 'utm_medium' => 'insideplugin' )
45 | );
46 | $args = array_map( 'urlencode', $args );
47 | $url = trailingslashit( self::BSR_URL ) . ltrim( $path, '/' );
48 | $url = add_query_arg( $args, $url );
49 | if ( $hash ) {
50 | $url .= '#' . $hash;
51 | }
52 |
53 | return $url;
54 | }
55 |
56 | /**
57 | * Generate WP Engine site URL with correct UTM tags.
58 | *
59 | * @param string $path
60 | * @param array $args
61 | * @param string $hash
62 | *
63 | * @return string
64 | */
65 | public static function wpe_url( $path = '', $args = array(), $hash = '' ) {
66 | $args = wp_parse_args(
67 | $args,
68 | [
69 | 'utm_medium' => 'referral',
70 | 'utm_campaign' => 'bx_prod_referral',
71 | ]
72 | );
73 | $args = array_map( 'urlencode', $args );
74 | $url = trailingslashit( self::WPE_URL ) . ltrim( $path, '/' );
75 | $url = add_query_arg( $args, $url );
76 |
77 | if ( $hash ) {
78 | $url .= '#' . $hash;
79 | }
80 |
81 | return $url;
82 | }
83 |
84 | /**
85 | * Get the plugin page url
86 | *
87 | * @return string
88 | */
89 | public static function plugin_page_url() {
90 | return menu_page_url( 'better-search-replace', false );
91 | }
92 |
93 | /**
94 | * Is current admin screen for bsr.
95 | *
96 | * @return bool
97 | */
98 | public static function is_bsr_screen() {
99 | $screen = get_current_screen();
100 |
101 | return $screen->base === 'tools_page_better-search-replace';
102 | }
103 |
104 | /**
105 | * Ensures intent by verifying that a user was referred from another admin
106 | * page with the correct security nonce, and that user has the capability
107 | * level to use the plugin.
108 | *
109 | * @param int|string $action The nonce action.
110 | * @param string $query_arg Key to check for nonce in `$_REQUEST`.
111 | *
112 | * @return bool
113 | */
114 | public static function check_admin_referer( $action, $query_arg ) {
115 | return check_admin_referer( $action, $query_arg ) && bsr_enabled_for_user();
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/includes/index.php:
--------------------------------------------------------------------------------
1 | \n"
10 | "Language-Team: PNTE \n"
11 | "MIME-Version: 1.0\n"
12 | "Content-Type: text/plain; charset=UTF-8\n"
13 | "Content-Transfer-Encoding: 8bit\n"
14 | "Language: es\n"
15 | "Plural-Forms: nplurals=2; plural=(n != 1);\n"
16 | "X-Generator: Poedit 1.6.3\n"
17 | "X-Poedit-Basepath: ..\n"
18 | "X-Poedit-KeywordsList: __;_e;__ngettext:1,2;_n:1,2;__ngettext_noop:1,2;_n_noop:1,2;_c,_nc:4c,1,2;_x:1,2c;_nx:4c,1,2;_nx_noop:4c,1,2;_ex:1,2c;esc_attr__;esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c\n"
19 | "X-Poedit-SourceCharset: UTF-8\n"
20 | "X-Poedit-SearchPath-0: .\n"
21 |
22 | #: includes/class-bsr-admin.php:71
23 | msgid "No search string was defined, please enter a URL or string to search for."
24 | msgstr "Bitte gib ein, wonach die Datenbank durchsucht werden soll (z. B. eine URL)."
25 |
26 | #: includes/class-bsr-admin.php:72
27 | msgid "Please select the tables that you want to update."
28 | msgstr "Bitte wähle die Tabellen aus, die durchsucht werden sollen."
29 |
30 | #: includes/class-bsr-admin.php:73
31 | msgid "An error occurred processing your request. Try decreasing the \"Max Page Size\", or contact support."
32 | msgstr "Ein Fehler ist aufgetreten. Versuche entweder die \"Max. Seiten-Anzahl\" zu verringern, oder wende dich an unseren Support."
33 |
34 | #. #-#-#-#-# plugin.pot (Better Search Replace 1.2.2) #-#-#-#-#
35 | #. Plugin Name of the plugin/theme
36 | #: includes/class-bsr-admin.php:85
37 | #: templates/bsr-dashboard.php:29
38 | msgid "Better Search Replace"
39 | msgstr "Better Search Replace "
40 |
41 | #: includes/class-bsr-admin.php:105
42 | msgid "DRY RUN: %d tables were searched, %d cells were found that need to be updated, and %d changes were made.
Click here for more details, or use the form below to run the search/replace.
"
43 | msgstr "TESTLAUF: %d Tabellen wurden durchsucht, %d Tabellenzellen wurden gefunden, die aktualisiert werden sollen. %d Änderungen wurden vorgenommen.
Für mehr Details zum Testlauf hier klicken .
"
44 |
45 | #: includes/class-bsr-admin.php:112
46 | msgid "During the search/replace, %d tables were searched, with %d cells changed in %d updates.
Click here for more details.
"
47 | msgstr "Beim Suchen/Ersetzen wurden %d Tabellen mit insgesamt %d Zellen durchsucht. %d Aktualisierungen wurden vorgenommen.
Für mehr Details zur Aktualisierung hier klicken .
"
48 |
49 | #: includes/class-bsr-admin.php:212
50 | msgid "Table"
51 | msgstr "Tabelle"
52 |
53 | #: includes/class-bsr-admin.php:212
54 | msgid "Changes Found"
55 | msgstr "Änderungen gefunden"
56 |
57 | #: includes/class-bsr-admin.php:212
58 | msgid "Rows Updated"
59 | msgstr "Zeilen aktualisiert"
60 |
61 | #: includes/class-bsr-admin.php:212
62 | msgid "Time"
63 | msgstr "Zeit"
64 |
65 | #: includes/class-bsr-admin.php:233
66 | msgid "Want even more details, easy database migrations, and saved search/replace profiles?"
67 | msgstr "Du möchtest noch mehr Einstellungsmöglichkeiten, eine einfache Datenbank-Migration und die Möglichkeit Suchen/Ersetzen-Profile anzulegen?"
68 |
69 | #: includes/class-bsr-admin.php:234
70 | msgid "Learn more about the pro version"
71 | msgstr "Lerne die Pro-Version kennen"
72 |
73 | #: includes/class-bsr-admin.php:279
74 | msgid "Upgrade to Pro"
75 | msgstr "Upgrade auf die Pro-Version"
76 |
77 | #: includes/class-bsr-db.php:81
78 | msgid "(%s MB)"
79 | msgstr "(%s MB)"
80 |
81 | #: includes/class-bsr-db.php:251
82 | msgid "Error updating row: %d."
83 | msgstr "Fehler beim Aktualisieren in Zeile: %d."
84 |
85 | #: includes/class-bsr-db.php:257
86 | msgid "Row %d has no primary key, manual change needed."
87 | msgstr "Zeile %d hat keinen Primärschlüssel. Du musst sie manuell ändern."
88 |
89 | #: templates/bsr-dashboard.php:36
90 | msgid "Search/Replace"
91 | msgstr "Suchen/Ersetzen"
92 |
93 | #: templates/bsr-dashboard.php:37
94 | msgid "Settings"
95 | msgstr "Einstellungen"
96 |
97 | #: templates/bsr-dashboard.php:38
98 | msgid "Help"
99 | msgstr "Hilfe"
100 |
101 | #: templates/bsr-help.php:17
102 | msgid "Help & Troubleshooting"
103 | msgstr "Hilfe & Fehlerbehebung"
104 |
105 | #: templates/bsr-help.php:19
106 | msgid "Free support is available on the plugin support forums ."
107 | msgstr "Kostenlosen Support gibt es im Plugin Support-Forum ."
108 |
109 | #: templates/bsr-help.php:21
110 | msgid "For premium features and priority email support, upgrade to pro ."
111 | msgstr "Weitere Premium-Features und schneller Support per E-Mail: Upgrade auf die Pro-Version ."
112 |
113 | #: templates/bsr-help.php:23
114 | msgid "Found a bug or have a feature request? Please submit an issue on GitHub !"
115 | msgstr "Du hast einen Fehler gefunden? Du wünschst dir eine neue Funktion? Schreib uns auf GitHub !"
116 |
117 | #: templates/bsr-help.php:29
118 | msgid "Download System Info"
119 | msgstr "System-Info herunterladen"
120 |
121 | #: templates/bsr-search-replace.php:21
122 | msgid "This tool allows you to search and replace text in your database (supports serialized arrays and objects)."
123 | msgstr "Mit diesem Tool kannst du Zeichenketten in der Datenbank suchen und durch andere ersetzen (serialisierte Arrays und Objekte werden unterstützt)."
124 |
125 | #: templates/bsr-search-replace.php:22
126 | msgid "To get started, use the form below to enter the text to be replaced and select the tables to update."
127 | msgstr "Gib im Formular an, welche Zeichenkette gesucht und ersetzt werden soll. Wähle aus, welche Tabellen der Datenbank durchsucht werden sollen."
128 |
129 | #: templates/bsr-search-replace.php:23
130 | msgid "WARNING: Make sure you backup your database before using this plugin!"
131 | msgstr "Achtung: Mach' bitte ein Backup von deiner Datenbank bevor du dieses Plugin benutzt!"
132 |
133 | #: templates/bsr-search-replace.php:28
134 | msgid "Search for"
135 | msgstr "Suchen nach:"
136 |
137 | #: templates/bsr-search-replace.php:33
138 | msgid "Replace with"
139 | msgstr "Ersetzen durch:"
140 |
141 | #: templates/bsr-search-replace.php:38
142 | msgid "Select tables"
143 | msgstr "Tabellen auswählen:"
144 |
145 | #: templates/bsr-search-replace.php:41
146 | msgid "Select multiple tables with Ctrl-Click for Windows or Cmd-Click for Mac."
147 | msgstr "Steurungs-/Befehlstaste (Win/Mac) oder SHIFT gedrückt halten, um mehrere Tabellen auszuwählen."
148 |
149 | #: templates/bsr-search-replace.php:46
150 | msgid "Case-Insensitive?"
151 | msgstr "Groß -und Kleinschreibung ignorieren?"
152 |
153 | #: templates/bsr-search-replace.php:49
154 | msgid "Searches are case-sensitive by default."
155 | msgstr "Groß- und Kleinschreibung wird bei der Suche standardmäßig beachtet"
156 |
157 | #: templates/bsr-search-replace.php:54
158 | msgid "Replace GUIDs? "
159 | msgstr "Auch GUIDs ersetzen? "
160 |
161 | #: templates/bsr-search-replace.php:57
162 | msgid "If left unchecked, all database columns titled 'guid' will be skipped."
163 | msgstr "Lasse das Feld frei, um alle Datenbank-Spalten mit dem Titel 'guid' beim Suchen/Ersetzen zu überspringen (empfohlen)."
164 |
165 | #: templates/bsr-search-replace.php:62
166 | msgid "Run as dry run?"
167 | msgstr "Testlauf?"
168 |
169 | #: templates/bsr-search-replace.php:65
170 | msgid "If checked, no changes will be made to the database, allowing you to check the results beforehand."
171 | msgstr "Beim Testlauf wird die Datenbank nicht verändert. So kannst du vorher prüfen, welche Ersetzungen vorgenommen werden."
172 |
173 | #: templates/bsr-search-replace.php:76
174 | msgid "Run Search/Replace"
175 | msgstr "Suchen/Ersetzen starten"
176 |
177 | #: templates/bsr-settings.php:27
178 | msgid "Max Page Size"
179 | msgstr "Max. Seiten-Anzahl"
180 |
181 | #: templates/bsr-settings.php:31
182 | msgid "Current Setting: "
183 | msgstr "Aktuelle Einstellung: "
184 |
185 | #: templates/bsr-settings.php:33
186 | msgid "If you're noticing timeouts or getting a white screen while running a search replace, try decreasing this value."
187 | msgstr "Verringere diesen Wert, wenn dein Datenbank-Server ein Timeout zurückmeldet oder du nur einen weißen Screen siehst, während das Suchen/Ersetzen läuft. "
188 |
189 | #. Plugin URI of the plugin/theme
190 | msgid "http://expandedfronts.com/better-search-replace"
191 | msgstr "http://expandedfronts.com/better-search-replace"
192 |
193 | #. Description of the plugin/theme
194 | msgid "A small plugin for running a search/replace on your WordPress database."
195 | msgstr "Ein Plugin mit dem Zeichenketten in deiner WordPress-Datenbank gesucht und ersetzt werden können."
196 |
197 | #. Author of the plugin/theme
198 | msgid "Expanded Fronts"
199 | msgstr "Expanded Fronts"
200 |
201 | #. Author URI of the plugin/theme
202 | msgid "http://expandedfronts.com"
203 | msgstr "http://expandedfronts.com"
204 |
205 |
--------------------------------------------------------------------------------
/languages/better-search-replace-es_ES.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deliciousbrains/better-search-replace/8d4bce24c96f431f5ec8abb4232c0481862c9119/languages/better-search-replace-es_ES.mo
--------------------------------------------------------------------------------
/languages/better-search-replace-es_ES.po:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2014
2 | # This file is distributed under the same license as the plugin package.
3 | msgid ""
4 | msgstr ""
5 | "Project-Id-Version: Better Search Replace en español\n"
6 | "Report-Msgid-Bugs-To: http://wordpress.org/plugins/better-search-replace\n"
7 | "POT-Creation-Date: 2015-01-09 12:49+0100\n"
8 | "PO-Revision-Date: 2015-01-09 12:59+0100\n"
9 | "Last-Translator: Eduardo Larequi \n"
10 | "Language-Team: PNTE \n"
11 | "Language: es\n"
12 | "MIME-Version: 1.0\n"
13 | "Content-Type: text/plain; charset=UTF-8\n"
14 | "Content-Transfer-Encoding: 8bit\n"
15 | "Plural-Forms: nplurals=2; plural=(n != 1);\n"
16 | "X-Generator: Poedit 1.6.3\n"
17 | "X-Poedit-Basepath: ..\n"
18 | "X-Poedit-KeywordsList: __;_e;__ngettext:1,2;_n:1,2;__ngettext_noop:1,2;"
19 | "_n_noop:1,2;_c,_nc:4c,1,2;_x:1,2c;_nx:4c,1,2;_nx_noop:4c,1,2;_ex:1,2c;"
20 | "esc_attr__;esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c\n"
21 | "X-Poedit-SourceCharset: UTF-8\n"
22 | "X-Poedit-SearchPath-0: .\n"
23 |
24 | #: includes/class-better-search-replace-admin.php:141
25 | msgid ""
26 | "No search string was defined, please enter a URL or string to search for."
27 | msgstr ""
28 | "No se ha definido ninguna cadena de búsqueda; por favor, escribe una URL o "
29 | "cadena que buscar."
30 |
31 | #: includes/class-better-search-replace-admin.php:144
32 | msgid "Please select the tables that you want to update."
33 | msgstr "Por favor, selecciona las tablas que quieres actualizar."
34 |
35 | #: includes/class-better-search-replace-admin.php:153
36 | #, php-format
37 | msgid ""
38 | "DRY RUN: %d tables were searched, "
39 | "%d cells were found that need to be updated, and "
40 | "%d changes were made.
Click here for more details, or click the submit "
42 | "button below to run the search/replace.
"
43 | msgstr ""
44 | "EJECUCIÓN EN SECO: se hn realizado búsquedas en "
45 | "%d tablas, se han encontrado %d celdas que deben "
46 | "ser actualizadas, y se han realizado %d cambios.
Haz clic aquí para ver más detalles, o haz clic en el botón \"Enviar"
49 | "\" que tienes a continuación para ejecutar la búsqueda y sustitución.
"
50 |
51 | #: includes/class-better-search-replace-admin.php:160
52 | #, php-format
53 | msgid ""
54 | "During the search/replace, %d tables were searched, with "
55 | "%d cells changed in %d updates.
Click here"
57 | "a> for more details.
"
58 | msgstr ""
59 | "Durante la búsqueda y sustitución, se han realizado búsquedas en "
60 | "%d tablas, y se han modificado %d celdas en "
61 | "%d actualizaciones.
Haz clic aquí para "
63 | "ver más detalles.
"
64 |
65 | #: templates/bsr-dashboard.php:17
66 | msgid "Better Search Replace"
67 | msgstr "Better Search Replace"
68 |
69 | #: templates/bsr-dashboard.php:19
70 | msgid ""
71 | "This tool allows you to search and replace text in your database (supports "
72 | "serialized arrays and objects)."
73 | msgstr ""
74 | "Esta herramienta permite buscar y sustituir texto en la base de datos; "
75 | "soporta matrices y objetos serializados."
76 |
77 | #: templates/bsr-dashboard.php:20
78 | msgid ""
79 | "To get started, use the form below to enter the text to be replaced and "
80 | "select the tables to update."
81 | msgstr ""
82 | "Para comenzar, utiliza el formulario que tienes a continuación para escribir "
83 | "el texto que será sustituido y selecciona las tablas que se actualizarán."
84 |
85 | #: templates/bsr-dashboard.php:21
86 | msgid ""
87 | "WARNING: Make sure you backup your database before using "
88 | "this plugin!"
89 | msgstr ""
90 | "ATENCIÓN: asegúrate de hacer una copia de seguridad de tu "
91 | "base de datos antes de utilizar este plugin."
92 |
93 | #: templates/bsr-dashboard.php:28
94 | msgid "Search for"
95 | msgstr "Buscar"
96 |
97 | #: templates/bsr-dashboard.php:33
98 | msgid "Replace with"
99 | msgstr "Sustituir con"
100 |
101 | #: templates/bsr-dashboard.php:38
102 | msgid "Select tables"
103 | msgstr "Seleccionar tablas"
104 |
105 | #: templates/bsr-dashboard.php:41
106 | msgid ""
107 | "Select multiple tables with Ctrl-Click for Windows or Cmd-Click for Mac."
108 | msgstr ""
109 | "Selecciona múltiples tablas con Ctrl+Clic (en Windows) o Cmd+Clic (en Mac)."
110 |
111 | #: templates/bsr-dashboard.php:46
112 | msgid ""
113 | "Replace GUIDs? "
115 | msgstr ""
116 | "¿Quieres "
118 | "sustituir los GUIDs ? "
119 |
120 | #: templates/bsr-dashboard.php:49
121 | msgid "If left unchecked, all database columns titled 'guid' will be skipped."
122 | msgstr ""
123 | "Si no activas esta opción, se omitirán todas las columnas de las bases de "
124 | "datos tituladas 'guid'."
125 |
126 | #: templates/bsr-dashboard.php:54
127 | msgid "Run as dry run?"
128 | msgstr "¿Quieres ejecutar \"en seco\"?"
129 |
130 | #: templates/bsr-dashboard.php:57
131 | msgid ""
132 | "If checked, no changes will be made to the database, allowing you to check "
133 | "the results beforehand."
134 | msgstr ""
135 | "Si activas esta opción, no se realizará ningún cambio en la base de datos, "
136 | "lo cual te permite verificar los resultados de antemano."
137 |
--------------------------------------------------------------------------------
/languages/better-search-replace-fr_FR.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deliciousbrains/better-search-replace/8d4bce24c96f431f5ec8abb4232c0481862c9119/languages/better-search-replace-fr_FR.mo
--------------------------------------------------------------------------------
/languages/better-search-replace-fr_FR.po:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2015 Better Search Replace
2 | # This file is distributed under the same license as the Better Search Replace package.
3 | msgid ""
4 | msgstr ""
5 | "Project-Id-Version: Better Search Replace 1.0.2\n"
6 | "Report-Msgid-Bugs-To: http://wordpress.org/support/plugin/better-search-replace\n"
7 | "POT-Creation-Date: 2015-02-05 04:52:47+00:00\n"
8 | "MIME-Version: 1.0\n"
9 | "Content-Type: text/plain; charset=UTF-8\n"
10 | "Content-Transfer-Encoding: 8bit\n"
11 | "PO-Revision-Date: 2015-05-12 10:08-0500\n"
12 | "Plural-Forms: nplurals=2; plural=(n > 1);\n"
13 | "Last-Translator: TWF \n"
14 | "Language-Team: TWF \n"
15 | "Language: fr\n"
16 | "X-Generator: Poedit 1.7.6\n"
17 | "X-Poedit-SourceCharset: UTF-8\n"
18 | "X-Poedit-KeywordsList: __;_e\n"
19 | "X-Poedit-Basepath: .\n"
20 | "X-Poedit-SearchPath-0: ..\n"
21 |
22 | #. Plugin Name of the plugin/theme
23 | #: includes/class-better-search-replace-admin.php:69 templates/bsr-dashboard.php:17
24 | msgid "Better Search Replace"
25 | msgstr "Better Search Replace"
26 |
27 | #: includes/class-better-search-replace-admin.php:138
28 | msgid "No search string was defined, please enter a URL or string to search for."
29 | msgstr ""
30 | "Aucune chaîne de recherche a été définie, entrez une URL ou une chaîne à rechercher."
31 |
32 | #: includes/class-better-search-replace-admin.php:141
33 | msgid "Please select the tables that you want to update."
34 | msgstr "Sélectionnez les tables que vous souhaitez mettre à jour."
35 |
36 | #: includes/class-better-search-replace-admin.php:150
37 | msgid ""
38 | "DRY RUN: %d tables were searched, %d"
39 | "strong> cells were found that need to be updated, and %d changes "
40 | "were made.
Click "
41 | "here for more details, or use the form below to run the search/replace.
"
42 | msgstr ""
43 | "Résultat de l'essai : %d tables ont été "
44 | "parcourues, %d chaînes trouvées qui peuvent être mises à jour et "
45 | "%d modifications auraient pu être apportées.
Cliquez ici pour plus de détails, "
47 | "ou utilisez le formulaire ci-dessous pour exécuter la recherche/remplace.
"
48 |
49 | #: includes/class-better-search-replace-admin.php:157
50 | msgid ""
51 | "During the search/replace, %d tables were searched, with "
52 | "%d cells changed in %d updates.
Click here for more details.
"
54 | msgstr ""
55 | "Pendant la recherche/remplace, %d tables ont été fouillés, avec "
56 | "%d cellules changées dans %d mises à jour."
57 | "p>
Cliquez ici "
58 | "pour plus de détails.
"
59 |
60 | #: templates/bsr-dashboard.php:19
61 | msgid ""
62 | "This tool allows you to search and replace text in your database (supports "
63 | "serialized arrays and objects)."
64 | msgstr ""
65 | "Cet outil vous permet de rechercher et remplacer du texte dans votre base de données "
66 | "(prend en charge la sérialisation des tables et objets)."
67 |
68 | #: templates/bsr-dashboard.php:20
69 | msgid ""
70 | "To get started, use the form below to enter the text to be replaced and select the "
71 | "tables to update."
72 | msgstr ""
73 | "Pour commencer, utiliser le formulaire ci-dessous pour entrer dans le texte pour le "
74 | "remplacement et sélectionnez les tables à mettre à jour."
75 |
76 | #: templates/bsr-dashboard.php:21
77 | msgid ""
78 | "WARNING: Make sure you backup your database before using this "
79 | "plugin!"
80 | msgstr ""
81 | "Avertissement : Assurez-vous que vous avez sauvegardé votre base de "
82 | "données avant d'utiliser ce plugin !"
83 |
84 | #: templates/bsr-dashboard.php:28
85 | msgid "Search for"
86 | msgstr "Rechercher"
87 |
88 | #: templates/bsr-dashboard.php:33
89 | msgid "Replace with"
90 | msgstr "Remplacer avec"
91 |
92 | #: templates/bsr-dashboard.php:38
93 | msgid "Select tables"
94 | msgstr "Dans les tables"
95 |
96 | #: templates/bsr-dashboard.php:41
97 | msgid "Select multiple tables with Ctrl-Click for Windows or Cmd-Click for Mac."
98 | msgstr "Sélectionnez plusieurs tables avec la touche CTRL+clic ou CMD+clic pour Mac"
99 |
100 | #: templates/bsr-dashboard.php:46
101 | msgid ""
102 | "Replace GUIDs? "
104 | msgstr ""
105 | "Remplacez les GUID ? En savoir plus sur "
107 | "les GUID "
108 |
109 | #: templates/bsr-dashboard.php:49
110 | msgid "If left unchecked, all database columns titled 'guid' will be skipped."
111 | msgstr "Si décoché, toutes les colonnes 'guid' de la base de données seront igniorés."
112 |
113 | #: templates/bsr-dashboard.php:54
114 | msgid "Run as dry run?"
115 | msgstr "Juste faire un test ?"
116 |
117 | #: templates/bsr-dashboard.php:57
118 | msgid ""
119 | "If checked, no changes will be made to the database, allowing you to check the "
120 | "results beforehand."
121 | msgstr ""
122 | "Si coché, aucun changement ne sera apporté à la base de données, vous aurez un bilan "
123 | "des résultats possibles"
124 |
125 | #: templates/bsr-dashboard.php:66
126 | msgid "Run Search/Replace"
127 | msgstr "Rechercher/Remplacer"
128 |
129 | #. Plugin URI of the plugin/theme
130 | msgid "http://expandedfronts.com/better-search-replace"
131 | msgstr "http://expandedfronts.com/better-search-replace"
132 |
133 | #. Description of the plugin/theme
134 | msgid "A small plugin for running a search/replace on your WordPress database."
135 | msgstr ""
136 | "Un petit plugin pour rechercher et remplacer des cabine dans votre base de données "
137 | "WordPress."
138 |
139 | #. Author of the plugin/theme
140 | msgid "Expanded Fronts"
141 | msgstr "Expanded Fronts"
142 |
143 | #. Author URI of the plugin/theme
144 | msgid "http://expandedfronts.com"
145 | msgstr "http://expandedfronts.com"
146 |
--------------------------------------------------------------------------------
/languages/better-search-replace.pot:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2025 WP Engine
2 | # This file is distributed under the GPL-3.0.
3 | msgid ""
4 | msgstr ""
5 | "Project-Id-Version: Better Search Replace 1.4.10\n"
6 | "Report-Msgid-Bugs-To: "
7 | "http://wordpress.org/support/plugin/better-search-replace\n"
8 | "POT-Creation-Date: 2025-01-09 17:40:23+00:00\n"
9 | "MIME-Version: 1.0\n"
10 | "Content-Type: text/plain; charset=utf-8\n"
11 | "Content-Transfer-Encoding: 8bit\n"
12 | "PO-Revision-Date: 2025-MO-DA HO:MI+ZONE\n"
13 | "Last-Translator: Delicious Brains \n"
14 | "Language-Team: Delicious Brains \n"
15 | "Language: en\n"
16 | "Plural-Forms: nplurals=2; plural=(n != 1);\n"
17 | "X-Poedit-Country: United States\n"
18 | "X-Poedit-SourceCharset: UTF-8\n"
19 | "X-Poedit-KeywordsList: "
20 | "__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_"
21 | "attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c;\n"
22 | "X-Poedit-Basepath: ../\n"
23 | "X-Poedit-SearchPath-0: .\n"
24 | "X-Poedit-Bookmarks: \n"
25 | "X-Textdomain-Support: yes\n"
26 | "X-Generator: grunt-wp-i18n 1.0.3\n"
27 |
28 | #: includes/class-bsr-admin.php:72
29 | msgid "No search string was defined, please enter a URL or string to search for."
30 | msgstr ""
31 |
32 | #: includes/class-bsr-admin.php:73
33 | msgid "Please select the tables that you want to update."
34 | msgstr ""
35 |
36 | #: includes/class-bsr-admin.php:74
37 | msgid ""
38 | "An error occurred processing your request. Try decreasing the \"Max Page "
39 | "Size\", or contact support."
40 | msgstr ""
41 |
42 | #: includes/class-bsr-admin.php:75
43 | msgid "Processing..."
44 | msgstr ""
45 |
46 | #. Plugin Name of the plugin/theme
47 | msgid "Better Search Replace"
48 | msgstr ""
49 |
50 | #: includes/class-bsr-admin.php:125
51 | msgid ""
52 | "DRY RUN: %1$d tables were searched, "
53 | "%2$d cells were found that need to be updated, and "
54 | "%3$d changes were made.
Click here for more "
56 | "details, or use the form below to run the search/replace.
"
57 | msgstr ""
58 |
59 | #: includes/class-bsr-admin.php:136
60 | msgid ""
61 | "During the search/replace, %1$d tables were searched, "
62 | "with %2$d cells changed in %3$d "
63 | "updates.
Click here for more details.
"
65 | msgstr ""
66 |
67 | #: includes/class-bsr-admin.php:234
68 | msgid "Table"
69 | msgstr ""
70 |
71 | #: includes/class-bsr-admin.php:234
72 | msgid "Changes Found"
73 | msgstr ""
74 |
75 | #: includes/class-bsr-admin.php:234
76 | msgid "Rows Updated"
77 | msgstr ""
78 |
79 | #: includes/class-bsr-admin.php:234
80 | msgid "Time"
81 | msgstr ""
82 |
83 | #: includes/class-bsr-admin.php:245
84 | msgid ""
85 | "UPGRADE to view details on the exact "
86 | "changes that will be made."
87 | msgstr ""
88 |
89 | #: includes/class-bsr-admin.php:256
90 | msgid " seconds"
91 | msgstr ""
92 |
93 | #: includes/class-bsr-admin.php:303
94 | msgid "Upgrade to Pro"
95 | msgstr ""
96 |
97 | #: includes/class-bsr-ajax.php:159
98 | msgid "Processing table %d of %d: %s"
99 | msgstr ""
100 |
101 | #: includes/class-bsr-db.php:85
102 | msgid "(%s MB)"
103 | msgstr ""
104 |
105 | #: includes/class-bsr-db.php:295
106 | msgid "Error updating row: %d."
107 | msgstr ""
108 |
109 | #: includes/class-bsr-plugin-footer.php:51
110 | #. translators: %1$s is a link to BSR's website, and %2$s is a link to WP
111 | #. Engine's website.
112 | msgid "%1$s is developed and maintained by %2$s."
113 | msgstr ""
114 |
115 | #: includes/class-bsr-plugin-footer.php:79
116 | msgid "Documentation"
117 | msgstr ""
118 |
119 | #: includes/class-bsr-plugin-footer.php:82
120 | msgid "Support"
121 | msgstr ""
122 |
123 | #: includes/class-bsr-plugin-footer.php:89
124 | msgid "Feedback"
125 | msgstr ""
126 |
127 | #: templates/bsr-dashboard.php:53
128 | msgid "Upgrade now and get 50% off"
129 | msgstr ""
130 |
131 | #: templates/bsr-dashboard.php:65 templates/bsr-search-replace.php:32
132 | msgid "Search/Replace"
133 | msgstr ""
134 |
135 | #: templates/bsr-dashboard.php:66 templates/bsr-settings.php:30
136 | msgid "Settings"
137 | msgstr ""
138 |
139 | #: templates/bsr-dashboard.php:67
140 | msgid "Help"
141 | msgstr ""
142 |
143 | #: templates/bsr-help.php:26
144 | msgid "Help & Troubleshooting"
145 | msgstr ""
146 |
147 | #: templates/bsr-help.php:35
148 | msgid "Free support is available on the plugin support forums ."
149 | msgstr ""
150 |
151 | #: templates/bsr-help.php:43
152 | msgid ""
153 | "Upgrade to "
154 | "gain access to premium features and priority email support."
155 | msgstr ""
156 |
157 | #: templates/bsr-help.php:51
158 | msgid ""
159 | "Found a bug or have a feature request? Please submit an issue on GitHub !"
161 | msgstr ""
162 |
163 | #: templates/bsr-help.php:61
164 | msgid "System Info"
165 | msgstr ""
166 |
167 | #: templates/bsr-search-replace.php:37
168 | msgid ""
169 | "Search and replace text in the database, including serialized arrays and "
170 | "objects. Be sure to back up your database before running this process."
171 | msgstr ""
172 |
173 | #: templates/bsr-search-replace.php:46
174 | msgid "Search for"
175 | msgstr ""
176 |
177 | #: templates/bsr-search-replace.php:51
178 | msgid "Replace with"
179 | msgstr ""
180 |
181 | #: templates/bsr-search-replace.php:59
182 | msgid "Select tables"
183 | msgstr ""
184 |
185 | #: templates/bsr-search-replace.php:61
186 | msgid "Select multiple tables with Ctrl-Click for Windows or Cmd-Click for Mac."
187 | msgstr ""
188 |
189 | #: templates/bsr-search-replace.php:73
190 | msgid "Additional Settings"
191 | msgstr ""
192 |
193 | #: templates/bsr-search-replace.php:84
194 | msgid "Case-Insensitive"
195 | msgstr ""
196 |
197 | #: templates/bsr-search-replace.php:85
198 | msgid "Searches are case-sensitive by default."
199 | msgstr ""
200 |
201 | #: templates/bsr-search-replace.php:95
202 | msgid "Replace GUIDs"
203 | msgstr ""
204 |
205 | #: templates/bsr-search-replace.php:96
206 | msgid "If left unchecked, all database columns titled 'guid' will be skipped."
207 | msgstr ""
208 |
209 | #: templates/bsr-search-replace.php:106
210 | msgid "Run as dry run"
211 | msgstr ""
212 |
213 | #: templates/bsr-search-replace.php:107
214 | msgid ""
215 | "If checked, no changes will be made to the database, allowing you to check "
216 | "the results beforehand."
217 | msgstr ""
218 |
219 | #: templates/bsr-search-replace.php:118
220 | msgid "Run Search/Replace"
221 | msgstr ""
222 |
223 | #: templates/bsr-settings.php:39
224 | msgid "Max Page Size"
225 | msgstr ""
226 |
227 | #: templates/bsr-settings.php:43
228 | msgid ""
229 | "If you notice timeouts or are unable to backup/import the database, try "
230 | "decreasing this value."
231 | msgstr ""
232 |
233 | #: templates/sidebar.php:4
234 | msgid "Upgrade"
235 | msgstr ""
236 |
237 | #: templates/sidebar.php:5
238 | msgid "Gain access to more database and migration features"
239 | msgstr ""
240 |
241 | #: templates/sidebar.php:9
242 | msgid "Preview database changes before they are saved"
243 | msgstr ""
244 |
245 | #: templates/sidebar.php:12
246 | msgid "Use regular expressions for complex string replacements"
247 | msgstr ""
248 |
249 | #: templates/sidebar.php:15
250 | msgid "Migrate full sites including themes, plugins, media, and database"
251 | msgstr ""
252 |
253 | #: templates/sidebar.php:18
254 | msgid "Export and import WordPress databases"
255 | msgstr ""
256 |
257 | #: templates/sidebar.php:21
258 | msgid "Email support"
259 | msgstr ""
260 |
261 | #: templates/sidebar.php:25
262 | msgid "Get up to 50% off your first year!"
263 | msgstr ""
264 |
265 | #: templates/sidebar.php:29
266 | msgid "Upgrade Now"
267 | msgstr ""
268 |
269 | #. Author URI of the plugin/theme
270 | msgid "https://bettersearchreplace.com"
271 | msgstr ""
272 |
273 | #. Description of the plugin/theme
274 | msgid "A small plugin for running a search/replace on your WordPress database."
275 | msgstr ""
276 |
277 | #. Author of the plugin/theme
278 | msgid "WP Engine"
279 | msgstr ""
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "better-search-replace",
3 | "version": "1.4.11-dev",
4 | "description": "A simple plugin for updating URLs or other text in a database.",
5 | "main": "index.js",
6 | "repository": "https://github.com/deliciousbrains/better-search-replace",
7 | "author": "Delicious Brains ",
8 | "license": "GPL-3.0-only",
9 | "devDependencies": {
10 | "grunt": "^1.6.1",
11 | "grunt-contrib-cssmin": "^4.0.0",
12 | "grunt-contrib-uglify": "^5.0.1",
13 | "grunt-contrib-watch": "^1.1.0",
14 | "grunt-wp-i18n": "^1.0.3"
15 | },
16 | "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
17 | }
18 |
--------------------------------------------------------------------------------
/templates/bsr-dashboard.php:
--------------------------------------------------------------------------------
1 | Better Search Replace.
5 | *
6 | * @link https://bettersearchreplace.com
7 | * @since 1.0.0
8 | *
9 | * @package Better_Search_Replace
10 | * @subpackage Better_Search_Replace/templates
11 | */
12 |
13 | // Prevent direct access.
14 | if ( ! defined( 'BSR_PATH' ) ) exit;
15 |
16 | // Determines which tab to display.
17 | $active_tab = isset( $_GET['tab'] ) ? $_GET['tab'] : 'bsr_search_replace';
18 |
19 | switch( $active_tab ) {
20 | case 'bsr_settings':
21 | $action = 'action="' . get_admin_url() . 'options.php' . '"';
22 | break;
23 | case 'bsr_help':
24 | $action = 'action="' . get_admin_url() . 'admin-post.php' . '"';
25 | break;
26 | default:
27 | $action = '';
28 | }
29 |
30 | if ( 'bsr_settings' === $active_tab ) {
31 | $action = get_admin_url() . 'options.php';
32 | } else {
33 | $action = get_admin_url() . 'admin-post.php';
34 | }
35 |
36 | ?>
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
62 |
63 |
70 |
71 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/templates/bsr-help.php:
--------------------------------------------------------------------------------
1 |
18 |
19 |
86 |
--------------------------------------------------------------------------------
/templates/bsr-search-replace.php:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/templates/bsr-settings.php:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
22 |
66 |
--------------------------------------------------------------------------------
/templates/sidebar.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/vendor/brumann/polyfill-unserialize/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016-2019 Denis Brumann
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/vendor/brumann/polyfill-unserialize/src/DisallowedClassesSubstitutor.php:
--------------------------------------------------------------------------------
1 | , ]` and
27 | * marks start and end positions of items to be ignored.
28 | *
29 | * @var array[]
30 | */
31 | private $ignoreItems = array();
32 |
33 | /**
34 | * @param string $serialized
35 | * @param string[] $allowedClasses
36 | */
37 | public function __construct($serialized, array $allowedClasses)
38 | {
39 | $this->serialized = $serialized;
40 | $this->allowedClasses = $allowedClasses;
41 |
42 | $this->buildIgnoreItems();
43 | $this->substituteObjects();
44 | }
45 |
46 | /**
47 | * @return string
48 | */
49 | public function getSubstitutedSerialized()
50 | {
51 | return $this->serialized;
52 | }
53 |
54 | /**
55 | * Identifies items to be ignored - like nested serializations in string literals.
56 | */
57 | private function buildIgnoreItems()
58 | {
59 | $offset = 0;
60 | while (preg_match(self::PATTERN_STRING, $this->serialized, $matches, PREG_OFFSET_CAPTURE, $offset)) {
61 | $length = (int)$matches[1][0]; // given length in serialized data (e.g. `s:123:"` --> 123)
62 | $start = $matches[2][1]; // offset position of quote character
63 | $end = $start + $length + 1;
64 | $offset = $end + 1;
65 |
66 | // serialized string nested in outer serialized string
67 | if ($this->ignore($start, $end)) {
68 | continue;
69 | }
70 |
71 | $this->ignoreItems[] = array($start, $end);
72 | }
73 | }
74 |
75 | /**
76 | * Substitutes disallowed object class names and respects items to be ignored.
77 | */
78 | private function substituteObjects()
79 | {
80 | $offset = 0;
81 | while (preg_match(self::PATTERN_OBJECT, $this->serialized, $matches, PREG_OFFSET_CAPTURE, $offset)) {
82 | $completeMatch = (string)$matches[0][0];
83 | $completeLength = strlen($completeMatch);
84 | $start = $matches[0][1];
85 | $end = $start + $completeLength;
86 | $leftBorder = (string)$matches[1][0];
87 | $className = (string)$matches[2][0];
88 | $objectSize = (int)$matches[3][0];
89 | $offset = $end + 1;
90 |
91 | // class name is actually allowed - skip this item
92 | if (in_array($className, $this->allowedClasses, true)) {
93 | continue;
94 | }
95 | // serialized object nested in outer serialized string
96 | if ($this->ignore($start, $end)) {
97 | continue;
98 | }
99 |
100 | $incompleteItem = $this->sanitizeItem($className, $leftBorder, $objectSize);
101 | $incompleteItemLength = strlen($incompleteItem);
102 | $offset = $start + $incompleteItemLength + 1;
103 |
104 | $this->replace($incompleteItem, $start, $end);
105 | $this->shift($end, $incompleteItemLength - $completeLength);
106 | }
107 | }
108 |
109 | /**
110 | * Replaces sanitized object class names in serialized data.
111 | *
112 | * @param string $replacement Sanitized object data
113 | * @param int $start Start offset in serialized data
114 | * @param int $end End offset in serialized data
115 | */
116 | private function replace($replacement, $start, $end)
117 | {
118 | $this->serialized = substr($this->serialized, 0, $start)
119 | . $replacement . substr($this->serialized, $end);
120 | }
121 |
122 | /**
123 | * Whether given offset positions should be ignored.
124 | *
125 | * @param int $start
126 | * @param int $end
127 | * @return bool
128 | */
129 | private function ignore($start, $end)
130 | {
131 | foreach ($this->ignoreItems as $ignoreItem) {
132 | if ($ignoreItem[0] <= $start && $ignoreItem[1] >= $end) {
133 | return true;
134 | }
135 | }
136 |
137 | return false;
138 | }
139 |
140 | /**
141 | * Shifts offset positions of ignore items by `$size`.
142 | * This is necessary whenever object class names have been
143 | * substituted which have a different length than before.
144 | *
145 | * @param int $offset
146 | * @param int $size
147 | */
148 | private function shift($offset, $size)
149 | {
150 | foreach ($this->ignoreItems as &$ignoreItem) {
151 | // only focus on items starting after given offset
152 | if ($ignoreItem[0] < $offset) {
153 | continue;
154 | }
155 | $ignoreItem[0] += $size;
156 | $ignoreItem[1] += $size;
157 | }
158 | }
159 |
160 | /**
161 | * Sanitizes object class item.
162 | *
163 | * @param string $className
164 | * @param int $leftBorder
165 | * @param int $objectSize
166 | * @return string
167 | */
168 | private function sanitizeItem($className, $leftBorder, $objectSize)
169 | {
170 | return sprintf(
171 | '%sO:22:"__PHP_Incomplete_Class":%d:{s:27:"__PHP_Incomplete_Class_Name";%s',
172 | $leftBorder,
173 | $objectSize + 1, // size of object + 1 for added string
174 | \serialize($className)
175 | );
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/vendor/brumann/polyfill-unserialize/src/Unserialize.php:
--------------------------------------------------------------------------------
1 | = 70000) {
18 | return \unserialize($serialized, $options);
19 | }
20 | if (!array_key_exists('allowed_classes', $options) || true === $options['allowed_classes']) {
21 | return \unserialize($serialized);
22 | }
23 | $allowedClasses = $options['allowed_classes'];
24 | if (false === $allowedClasses) {
25 | $allowedClasses = array();
26 | }
27 | if (!is_array($allowedClasses)) {
28 | $allowedClasses = array();
29 | trigger_error(
30 | 'unserialize(): allowed_classes option should be array or boolean',
31 | E_USER_WARNING
32 | );
33 | }
34 |
35 | $worker = new DisallowedClassesSubstitutor($serialized, $allowedClasses);
36 |
37 | return \unserialize($worker->getSubstitutedSerialized());
38 | }
39 | }
40 |
--------------------------------------------------------------------------------