Version Description
- Fixed some lingering potential HTTPS issues.
- Fixed result previews not cutting the excerpt making them excessively long.
- Fixed archive file skipping not accounting for letter casing in extensions.
- Introduced common media types to the file skipping procedure.
- Added default timeout periods, the plugin will no longer allow indefinite execution to work around http proxies.
- Added more translatable strings that were missed.
- Added Must-Use Plugins to individual plugin search.
- Made changes to the uninstall routine to ensure we remove any related database entries on removal.
Download this release
Release Info
Developer | Clorith |
Plugin | String locator |
Version | 2.2.0 |
Comparing to | |
See all releases |
Code changes from version 2.1.2 to 2.2.0
- changelog.txt +18 -0
- editor.php +11 -16
- options.php +5 -0
- readme.txt +19 -41
- resources/js/string-locator-search.js +21 -15
- string-locator.php +284 -166
- uninstall.php +7 -2
changelog.txt
CHANGED
@@ -1,3 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
= 2.0.3 =
|
2 |
* Added support for HHVM
|
3 |
* Improved inline documentation
|
1 |
+
= 2.1.2 =
|
2 |
+
* Fix for max execution times some times being interpreted as strings and failing when you it should be able to run indefinitely
|
3 |
+
* Fix for regex being enabled when you return to the search results, but you hadn't performed a regex search
|
4 |
+
* Resolved some code issues with functions being called improperly (future proofing)
|
5 |
+
|
6 |
+
= 2.1.1 =
|
7 |
+
* Improved error messages
|
8 |
+
* Add regex pattern validation before performing a search
|
9 |
+
* Fixed bug causing some searches to be identified as regex when they are not, leading to errors
|
10 |
+
* Fixed a bug that could cause the first file in every search chunk from being ignored
|
11 |
+
|
12 |
+
= 2.1.0 =
|
13 |
+
* Add support for configurations with infinite execution times
|
14 |
+
* Better code handling on RTL sites
|
15 |
+
* Exclude archive files, that we can't modify any way, from searches
|
16 |
+
* Display file path in the editor to identify which file is being modified
|
17 |
+
* Add support for RegEx string searches
|
18 |
+
|
19 |
= 2.0.3 =
|
20 |
* Added support for HHVM
|
21 |
* Improved inline documentation
|
editor.php
CHANGED
@@ -13,7 +13,8 @@
|
|
13 |
'uri' => 'https://wordpress.org/',
|
14 |
'name' => 'WordPress'
|
15 |
),
|
16 |
-
|
|
|
17 |
);
|
18 |
}
|
19 |
elseif ( 'theme' == $_GET['file-type'] ) {
|
@@ -65,12 +66,15 @@
|
|
65 |
}
|
66 |
?>
|
67 |
<div class="wrap">
|
68 |
-
<
|
69 |
-
<?php
|
|
|
|
|
|
|
70 |
<a href="<?php echo esc_url( $this_url . '&restore=true' ); ?>" class="button button-primary"><?php _e( 'Return to search results', 'string-locator' ); ?></a>
|
71 |
-
</
|
72 |
|
73 |
-
<form action="<?php echo ( is_ssl() ? '
|
74 |
<div class="string-locator-edit-wrap">
|
75 |
<textarea name="string-locator-editor-content" class="string-locator-editor" id="code-editor" data-editor-goto-line="<?php echo $_GET['string-locator-line']; ?>" data-editor-language="<?php echo $string_locator->string_locator_language; ?>" autofocus="autofocus"><?php echo esc_html( $editor_content ); ?></textarea>
|
76 |
</div>
|
@@ -97,7 +101,6 @@
|
|
97 |
</p>
|
98 |
|
99 |
<?php if ( isset( $details['parent'] ) && ! $details['parent'] ) { ?>
|
100 |
-
<!--
|
101 |
<div class="notice notice-warning inline below-h2">
|
102 |
<p>
|
103 |
<?php _e( 'It seems you are making direct edits to a theme.', 'string-locator' ); ?>
|
@@ -106,28 +109,20 @@
|
|
106 |
<p>
|
107 |
<?php _e( 'When making changes to a theme, it is recommended you make a <a href="https://codex.wordpress.org/Child_Themes">Child Theme</a>.', 'string-locator' ); ?>
|
108 |
</p>
|
109 |
-
|
110 |
-
<p>
|
111 |
-
<label>
|
112 |
-
<input type="checkbox" name="string-locator-make-child-theme" checked="checked">
|
113 |
-
<?php _e( 'Automatically create a new child theme for these edits', 'string-locator' ); ?>
|
114 |
-
</label>
|
115 |
-
</p>
|
116 |
</div>
|
117 |
|
118 |
<p>
|
119 |
|
120 |
</p>
|
121 |
-
-->
|
122 |
<?php } ?>
|
123 |
|
124 |
<?php if ( ! stristr( $file, 'wp-content' ) ) { ?>
|
125 |
<div class="notice notice-warning inline below-h2">
|
126 |
<p>
|
127 |
-
<strong
|
128 |
</p>
|
129 |
<p>
|
130 |
-
Keep in mind that edits to core files will be lost when WordPress is updated.
|
131 |
</p>
|
132 |
</div>
|
133 |
<?php } ?>
|
13 |
'uri' => 'https://wordpress.org/',
|
14 |
'name' => 'WordPress'
|
15 |
),
|
16 |
+
/* translators: The WordPress description, used when a core file is opened in the editor. */
|
17 |
+
'description' => __( 'WordPress is web software you can use to create a beautiful website or blog. We like to say that WordPress is both free and priceless at the same time.', 'string-locator' )
|
18 |
);
|
19 |
}
|
20 |
elseif ( 'theme' == $_GET['file-type'] ) {
|
66 |
}
|
67 |
?>
|
68 |
<div class="wrap">
|
69 |
+
<h1>
|
70 |
+
<?php
|
71 |
+
/* translators: Title on the editor page. */
|
72 |
+
_e( 'String Locator - Code Editor', 'string-locator' );
|
73 |
+
?>
|
74 |
<a href="<?php echo esc_url( $this_url . '&restore=true' ); ?>" class="button button-primary"><?php _e( 'Return to search results', 'string-locator' ); ?></a>
|
75 |
+
</h1>
|
76 |
|
77 |
+
<form action="<?php echo ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; ?>" id="string-locator-edit-form" method="post">
|
78 |
<div class="string-locator-edit-wrap">
|
79 |
<textarea name="string-locator-editor-content" class="string-locator-editor" id="code-editor" data-editor-goto-line="<?php echo $_GET['string-locator-line']; ?>" data-editor-language="<?php echo $string_locator->string_locator_language; ?>" autofocus="autofocus"><?php echo esc_html( $editor_content ); ?></textarea>
|
80 |
</div>
|
101 |
</p>
|
102 |
|
103 |
<?php if ( isset( $details['parent'] ) && ! $details['parent'] ) { ?>
|
|
|
104 |
<div class="notice notice-warning inline below-h2">
|
105 |
<p>
|
106 |
<?php _e( 'It seems you are making direct edits to a theme.', 'string-locator' ); ?>
|
109 |
<p>
|
110 |
<?php _e( 'When making changes to a theme, it is recommended you make a <a href="https://codex.wordpress.org/Child_Themes">Child Theme</a>.', 'string-locator' ); ?>
|
111 |
</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
112 |
</div>
|
113 |
|
114 |
<p>
|
115 |
|
116 |
</p>
|
|
|
117 |
<?php } ?>
|
118 |
|
119 |
<?php if ( ! stristr( $file, 'wp-content' ) ) { ?>
|
120 |
<div class="notice notice-warning inline below-h2">
|
121 |
<p>
|
122 |
+
<strong><?php _e( 'Warning:', 'string-locator' ); ?></strong> <?php _e( 'You appear to be editing a Core file.', 'string-locator' ); ?>
|
123 |
</p>
|
124 |
<p>
|
125 |
+
<?php _e( 'Keep in mind that edits to core files will be lost when WordPress is updated. Please consider <a href="https://make.wordpress.org/core/handbook/">contributing to WordPress core</a> instead.', 'string-locator' ); ?>
|
126 |
</p>
|
127 |
</div>
|
128 |
<?php } ?>
|
options.php
CHANGED
@@ -35,6 +35,11 @@ if ( isset( $_GET['restore'] ) ) {
|
|
35 |
<optgroup label="<?php _e( 'Themes', 'string-locator' ); ?>">
|
36 |
<?php echo String_Locator::get_themes_options( $search_location ); ?>
|
37 |
</optgroup>
|
|
|
|
|
|
|
|
|
|
|
38 |
<optgroup label="<?php _e( 'Plugins', 'string-locator' ); ?>">
|
39 |
<?php echo String_Locator::get_plugins_options( $search_location ); ?>
|
40 |
</optgroup>
|
35 |
<optgroup label="<?php _e( 'Themes', 'string-locator' ); ?>">
|
36 |
<?php echo String_Locator::get_themes_options( $search_location ); ?>
|
37 |
</optgroup>
|
38 |
+
<?php if ( String_Locator::has_mu_plugins() ) : ?>
|
39 |
+
<optgroup label="<?php _e( 'Must Use Plugins', 'string-locator' ); ?>">
|
40 |
+
<?php echo String_Locator::get_mu_plugins_options( $search_location ); ?>
|
41 |
+
</optgroup>
|
42 |
+
<?php endif; ?>
|
43 |
<optgroup label="<?php _e( 'Plugins', 'string-locator' ); ?>">
|
44 |
<?php echo String_Locator::get_plugins_options( $search_location ); ?>
|
45 |
</optgroup>
|
readme.txt
CHANGED
@@ -5,36 +5,23 @@ Plugin URI: http://wordpress.org/plugins/string-locator/
|
|
5 |
Donate link: https://www.paypal.me/clorith
|
6 |
Tags: theme, plugin, text, search, find, editor, syntax, highlight
|
7 |
Requires at least: 3.6
|
8 |
-
Tested up to: 4.
|
9 |
-
Stable tag: 2.
|
10 |
License: GPLv2 or later
|
11 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
12 |
|
13 |
-
Find and edit code in your themes and plugins
|
14 |
|
15 |
== Description ==
|
16 |
|
17 |
-
When working on themes and plugins you often notice a piece of text that appears hardcoded into the files, you need to modify it, but you don't know
|
18 |
|
19 |
-
Easily search through your themes, plugins or
|
20 |
You can then quickly make edits directly in your browser by clicking the link from the search results.
|
21 |
|
22 |
-
By default a
|
23 |
-
This drastically reduces the risk of breaking your site when making edits, but is
|
24 |
|
25 |
-
** Translations**
|
26 |
-
|
27 |
-
српски (Serbian) - Ognjen Djuraskovic
|
28 |
-
|
29 |
-
Español (Spanish) - Ognjen Djuraskovic
|
30 |
-
|
31 |
-
Deutsch (German) - [pixolin](http://profiles.wordpress.org/pixolin/)
|
32 |
-
|
33 |
-
== Installation ==
|
34 |
-
|
35 |
-
1. Upload the `string-locator` folder to the `/wp-content/plugins/` directory
|
36 |
-
2. Activate the plugin through the 'Plugins' menu in WordPress
|
37 |
-
3. You will find the String Locator option under then `Tools` menu
|
38 |
|
39 |
== Frequently asked questions ==
|
40 |
|
@@ -56,25 +43,16 @@ When writing your search string, make sure to wrap your search in forward slashe
|
|
56 |
3. Smart-Scan has detected an inconsistency in the use of braces
|
57 |
|
58 |
== Changelog ==
|
59 |
-
= 2.1.2 =
|
60 |
-
* Fix for max execution times some times being interpreted as strings and failing when you it should be able to run indefinitely
|
61 |
-
* Fix for regex being enabled when you return to the search results, but you hadn't performed a regex search
|
62 |
-
* Resolved some code issues with functions being called improperly (future proofing)
|
63 |
-
|
64 |
-
= 2.1.1 =
|
65 |
-
* Improved error messages
|
66 |
-
* Add regex pattern validation before performing a search
|
67 |
-
* Fixed bug causing some searches to be identified as regex when they are not, leading to errors
|
68 |
-
* Fixed a bug that could cause the first file in every search chunk from being ignored
|
69 |
-
|
70 |
-
= 2.1.0 =
|
71 |
-
* Add support for configurations with infinite execution times
|
72 |
-
* Better code handling on RTL sites
|
73 |
-
* Exclude archive files, that we can't modify any way, from searches
|
74 |
-
* Display file path in the editor to identify which file is being modified
|
75 |
-
* Add support for RegEx string searches
|
76 |
-
|
77 |
-
|
78 |
-
== Upgrade notice ==
|
79 |
|
80 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
Donate link: https://www.paypal.me/clorith
|
6 |
Tags: theme, plugin, text, search, find, editor, syntax, highlight
|
7 |
Requires at least: 3.6
|
8 |
+
Tested up to: 4.8
|
9 |
+
Stable tag: 2.2.0
|
10 |
License: GPLv2 or later
|
11 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
12 |
|
13 |
+
Find and edit code or texts in your themes and plugins
|
14 |
|
15 |
== Description ==
|
16 |
|
17 |
+
When working on themes and plugins you often notice a piece of text that appears hardcoded into the files, you need to modify it, but you don't know what theme or plugin it's in, and certainly not which individual file to look in.
|
18 |
|
19 |
+
Easily search through your themes, plugins or even WordPress core and be presented with a list of files, the matched text and what line of the file matched your search.
|
20 |
You can then quickly make edits directly in your browser by clicking the link from the search results.
|
21 |
|
22 |
+
By default a consistency check is performed when making edits to files, this will look for inconsistencies with braces, brackets and parenthesis that are often accidentally left in.
|
23 |
+
This drastically reduces the risk of breaking your site when making edits, but is in no way an absolute guarantee.
|
24 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
|
26 |
== Frequently asked questions ==
|
27 |
|
43 |
3. Smart-Scan has detected an inconsistency in the use of braces
|
44 |
|
45 |
== Changelog ==
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
|
47 |
+
= 2.2.0 =
|
48 |
+
* Fixed some lingering potential HTTPS issues.
|
49 |
+
* Fixed result previews not cutting the excerpt making them excessively long.
|
50 |
+
* Fixed archive file skipping not accounting for letter casing in extensions.
|
51 |
+
* Introduced common media types to the file skipping procedure.
|
52 |
+
* Added default timeout periods, the plugin will no longer allow indefinite execution to work around http proxies.
|
53 |
+
* Added more translatable strings that were missed.
|
54 |
+
* Added Must-Use Plugins to individual plugin search.
|
55 |
+
* Made changes to the uninstall routine to ensure we remove any related database entries on removal.
|
56 |
+
|
57 |
+
= Older entries =
|
58 |
+
See changelog.txt for the version history
|
resources/js/string-locator-search.js
CHANGED
@@ -31,7 +31,7 @@ jQuery(document).ready(function ($) {
|
|
31 |
}
|
32 |
}
|
33 |
).fail(function(xhr, textStatus, errorThrown) {
|
34 |
-
throw_error( errorThrown, string_locator.search_error );
|
35 |
});
|
36 |
};
|
37 |
|
@@ -58,13 +58,14 @@ jQuery(document).ready(function ($) {
|
|
58 |
string_locator.ajax_url,
|
59 |
search_request,
|
60 |
function ( response ) {
|
|
|
61 |
if ( ! response.success ) {
|
62 |
add_notice( string_locator.warning_title, response.data, 'warning' );
|
63 |
}
|
64 |
|
65 |
if ( undefined !== response.data.search ) {
|
66 |
$("#string-locator-search-progress").val( response.data.filenum );
|
67 |
-
$("#string-locator-feedback-text").html( response.data.next_file );
|
68 |
|
69 |
string_locator_append_result( response.data.search );
|
70 |
}
|
@@ -73,7 +74,7 @@ jQuery(document).ready(function ($) {
|
|
73 |
},
|
74 |
'json'
|
75 |
).fail(function(xhr, textStatus, errorThrown) {
|
76 |
-
throw_error( errorThrown, string_locator.search_error );
|
77 |
});
|
78 |
};
|
79 |
|
@@ -81,20 +82,25 @@ jQuery(document).ready(function ($) {
|
|
81 |
if ( $(".no-items", ".tools_page_string-locator").is(':visible') ) {
|
82 |
$(".no-items", ".tools_page_string-locator").hide();
|
83 |
}
|
|
|
|
|
|
|
84 |
|
85 |
total_entries.forEach( function ( entries ) {
|
86 |
-
|
|
|
87 |
|
88 |
-
|
89 |
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
|
97 |
-
|
|
|
98 |
}
|
99 |
}
|
100 |
} );
|
@@ -103,7 +109,7 @@ jQuery(document).ready(function ($) {
|
|
103 |
|
104 |
$("#string-locator-search-form").on( 'submit', function (e) {
|
105 |
e.preventDefault();
|
106 |
-
$("#string-locator-feedback-text").text(
|
107 |
$(".string-locator-feedback").show();
|
108 |
string_locator_search_active = true;
|
109 |
clear_string_locator_result_area();
|
@@ -127,12 +133,12 @@ jQuery(document).ready(function ($) {
|
|
127 |
return;
|
128 |
}
|
129 |
$("#string-locator-search-progress").attr( 'max', response.data.total ).val( response.data.current );
|
130 |
-
$("#string-locator-feedback-text").text(
|
131 |
perform_string_locator_single_search( response.data.total, 0 );
|
132 |
},
|
133 |
'json'
|
134 |
).fail(function(xhr, textStatus, errorThrown) {
|
135 |
-
throw_error( errorThrown, string_locator.search_error );
|
136 |
});
|
137 |
});
|
138 |
});
|
31 |
}
|
32 |
}
|
33 |
).fail(function(xhr, textStatus, errorThrown) {
|
34 |
+
throw_error( xhr.status + ' ' + errorThrown, string_locator.search_error );
|
35 |
});
|
36 |
};
|
37 |
|
58 |
string_locator.ajax_url,
|
59 |
search_request,
|
60 |
function ( response ) {
|
61 |
+
console.dir( response)
|
62 |
if ( ! response.success ) {
|
63 |
add_notice( string_locator.warning_title, response.data, 'warning' );
|
64 |
}
|
65 |
|
66 |
if ( undefined !== response.data.search ) {
|
67 |
$("#string-locator-search-progress").val( response.data.filenum );
|
68 |
+
$("#string-locator-feedback-text").html( string_locator.search_current_prefix + response.data.next_file );
|
69 |
|
70 |
string_locator_append_result( response.data.search );
|
71 |
}
|
74 |
},
|
75 |
'json'
|
76 |
).fail(function(xhr, textStatus, errorThrown) {
|
77 |
+
throw_error( xhr.status + ' ' + errorThrown, string_locator.search_error );
|
78 |
});
|
79 |
};
|
80 |
|
82 |
if ( $(".no-items", ".tools_page_string-locator").is(':visible') ) {
|
83 |
$(".no-items", ".tools_page_string-locator").hide();
|
84 |
}
|
85 |
+
if ( Array !== total_entries.constructor ) {
|
86 |
+
return false;
|
87 |
+
}
|
88 |
|
89 |
total_entries.forEach( function ( entries ) {
|
90 |
+
if ( entries ) {
|
91 |
+
for (var i = 0, amount = entries.length; i < amount; i++) {
|
92 |
|
93 |
+
var entry = entries[i];
|
94 |
|
95 |
+
if (undefined !== entry.stringresult) {
|
96 |
+
var builtHTML = '<tr>' +
|
97 |
+
'<td>' + entry.stringresult + '<div class="row-actions"><span class="edit"><a href="' + entry.editurl + '" aria-label="Edit">Edit</a></span></div></td>' +
|
98 |
+
'<td>' + entry.filename + '</td>' +
|
99 |
+
'<td>' + entry.linenum + '</td>' +
|
100 |
+
'</tr>';
|
101 |
|
102 |
+
$("tbody", ".tools_page_string-locator").append(builtHTML);
|
103 |
+
}
|
104 |
}
|
105 |
}
|
106 |
} );
|
109 |
|
110 |
$("#string-locator-search-form").on( 'submit', function (e) {
|
111 |
e.preventDefault();
|
112 |
+
$("#string-locator-feedback-text").text(string_locator.search_preparing );
|
113 |
$(".string-locator-feedback").show();
|
114 |
string_locator_search_active = true;
|
115 |
clear_string_locator_result_area();
|
133 |
return;
|
134 |
}
|
135 |
$("#string-locator-search-progress").attr( 'max', response.data.total ).val( response.data.current );
|
136 |
+
$("#string-locator-feedback-text").text(string_locator.search_started );
|
137 |
perform_string_locator_single_search( response.data.total, 0 );
|
138 |
},
|
139 |
'json'
|
140 |
).fail(function(xhr, textStatus, errorThrown) {
|
141 |
+
throw_error( xhr.status + ' ' + errorThrown, string_locator.search_error );
|
142 |
});
|
143 |
});
|
144 |
});
|
string-locator.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
* Plugin Name: String Locator
|
4 |
* Plugin URI: http://www.clorith.net/wordpress-string-locator/
|
5 |
* Description: Scan through theme and plugin files looking for text strings
|
6 |
-
* Version: 2.
|
7 |
* Author: Clorith
|
8 |
* Author URI: http://www.clorith.net
|
9 |
* Text Domain: string-locator
|
@@ -28,33 +28,50 @@
|
|
28 |
/**
|
29 |
* Class String_Locator
|
30 |
*/
|
31 |
-
class String_Locator
|
32 |
-
{
|
33 |
/**
|
34 |
-
* @var string $string_locator_language The code language used for the editing page
|
35 |
-
* @var string $version String Locator version number
|
36 |
-
* @var array
|
37 |
-
* @var bool
|
38 |
-
* @var string $plugin_url The URL to the plugins directory
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
*/
|
40 |
-
public
|
41 |
-
public
|
42 |
-
public
|
43 |
-
public
|
44 |
-
private $plugin_url
|
45 |
-
private $path_to_use
|
46 |
-
private $bad_http_codes
|
47 |
-
private $bad_file_types
|
48 |
-
private $excerpt_length
|
49 |
-
private $max_execution_time
|
50 |
-
private $start_execution_timer
|
51 |
-
private $max_memory_consumption
|
52 |
|
53 |
/**
|
54 |
* Construct the plugin
|
55 |
*/
|
56 |
-
function __construct()
|
57 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
/**
|
59 |
* Define class variables requiring expressions
|
60 |
*/
|
@@ -62,9 +79,13 @@ class String_Locator
|
|
62 |
$this->path_to_use = ( is_multisite() ? 'network/admin.php' : 'tools.php' );
|
63 |
$this->excerpt_length = apply_filters( 'string_locator_excerpt_length', 25 );
|
64 |
|
65 |
-
$this->max_execution_time
|
66 |
$this->start_execution_timer = microtime( true );
|
67 |
|
|
|
|
|
|
|
|
|
68 |
$this->set_memory_limit();
|
69 |
|
70 |
add_action( 'admin_menu', array( $this, 'populate_menu' ) );
|
@@ -85,7 +106,7 @@ class String_Locator
|
|
85 |
}
|
86 |
|
87 |
/**
|
88 |
-
* Sets up the memory limit variables
|
89 |
*
|
90 |
* @since 2.0.0
|
91 |
*
|
@@ -108,8 +129,10 @@ class String_Locator
|
|
108 |
}
|
109 |
|
110 |
/**
|
111 |
-
*
|
112 |
-
*
|
|
|
|
|
113 |
*
|
114 |
* @return array
|
115 |
*/
|
@@ -125,9 +148,9 @@ class String_Locator
|
|
125 |
}
|
126 |
|
127 |
/**
|
128 |
-
* Create a set of drop-down options for picking one of the available themes
|
129 |
*
|
130 |
-
* @param string $current The current selection option to match against
|
131 |
*
|
132 |
* @return string
|
133 |
*/
|
@@ -141,9 +164,9 @@ class String_Locator
|
|
141 |
|
142 |
$string_locate_themes = wp_get_themes();
|
143 |
|
144 |
-
foreach( $string_locate_themes AS $string_locate_theme_slug => $string_locate_theme ) {
|
145 |
$string_locate_theme_data = wp_get_theme( $string_locate_theme_slug );
|
146 |
-
$string_locate_value
|
147 |
|
148 |
$options .= sprintf(
|
149 |
'<option value="%s" %s>%s</option>',
|
@@ -157,9 +180,9 @@ class String_Locator
|
|
157 |
}
|
158 |
|
159 |
/**
|
160 |
-
* Create a set of drop-down options for picking one of the available plugins
|
161 |
*
|
162 |
-
* @param string $current The current selection option to match against
|
163 |
*
|
164 |
* @return string
|
165 |
*/
|
@@ -173,8 +196,7 @@ class String_Locator
|
|
173 |
|
174 |
$string_locate_plugins = get_plugins();
|
175 |
|
176 |
-
foreach( $string_locate_plugins AS $string_locate_plugin_path => $string_locate_plugin )
|
177 |
-
{
|
178 |
$string_locate_value = 'p-' . $string_locate_plugin_path;
|
179 |
|
180 |
$options .= sprintf(
|
@@ -189,18 +211,67 @@ class String_Locator
|
|
189 |
}
|
190 |
|
191 |
/**
|
192 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
193 |
*
|
194 |
-
* @return
|
195 |
*/
|
196 |
function ajax_get_directory_structure() {
|
197 |
-
if ( ! check_ajax_referer( 'string-locator-search', 'nonce', false ) ) {
|
|
|
|
|
198 |
|
199 |
$scan_path = $this->prepare_scan_path( $_POST['directory'] );
|
200 |
if ( is_file( $scan_path->path ) ) {
|
201 |
$files = array( $scan_path->path );
|
202 |
-
}
|
203 |
-
else {
|
204 |
$files = $this->ajax_scan_path( $scan_path->path );
|
205 |
}
|
206 |
|
@@ -229,7 +300,7 @@ class String_Locator
|
|
229 |
update_option( 'string-locator-search-overview', serialize( $store ), true );
|
230 |
update_option( 'string-locator-search-history', serialize( array() ) );
|
231 |
|
232 |
-
foreach( $file_chunks AS $count => $file_chunk ) {
|
233 |
update_option( 'string-locator-search-files-' . $count, serialize( $file_chunk ) );
|
234 |
}
|
235 |
|
@@ -244,8 +315,8 @@ class String_Locator
|
|
244 |
* @return bool
|
245 |
*/
|
246 |
function nearing_execution_limit() {
|
247 |
-
// Max execution time is 0 (infinite) in server config
|
248 |
-
if ( 0 === $this->max_execution_time ) {
|
249 |
return false;
|
250 |
}
|
251 |
|
@@ -255,6 +326,7 @@ class String_Locator
|
|
255 |
if ( $execution_time >= $this->max_execution_time ) {
|
256 |
return $execution_time;
|
257 |
}
|
|
|
258 |
return false;
|
259 |
}
|
260 |
|
@@ -266,25 +338,29 @@ class String_Locator
|
|
266 |
* @return bool
|
267 |
*/
|
268 |
function nearing_memory_limit() {
|
|
|
|
|
|
|
|
|
|
|
269 |
// We give our selves a 256k memory buffer, as we need to close off the script properly as well
|
270 |
$built_in_buffer = apply_filters( 'string-locator-extra-memory-buffer', 256000 );
|
271 |
-
$memory_use
|
272 |
|
273 |
if ( $memory_use >= $this->max_memory_consumption ) {
|
274 |
return $memory_use;
|
275 |
}
|
|
|
276 |
return false;
|
277 |
}
|
278 |
|
279 |
public static function absbool( $value ) {
|
280 |
if ( is_bool( $value ) ) {
|
281 |
$bool = $value;
|
282 |
-
}
|
283 |
-
else {
|
284 |
if ( 'false' == $value ) {
|
285 |
$bool = false;
|
286 |
-
}
|
287 |
-
else {
|
288 |
$bool = true;
|
289 |
}
|
290 |
}
|
@@ -293,17 +369,19 @@ class String_Locator
|
|
293 |
}
|
294 |
|
295 |
/**
|
296 |
-
* Search an individual file supplied via AJAX
|
297 |
*
|
298 |
* @since 1.9.0
|
299 |
*
|
300 |
-
* @return
|
301 |
*/
|
302 |
function ajax_file_search() {
|
303 |
-
if ( ! check_ajax_referer( 'string-locator-search', 'nonce', false ) ) {
|
|
|
|
|
304 |
|
305 |
$files_per_chunk = apply_filters( 'string-locator-files-per-array', 500 );
|
306 |
-
$response
|
307 |
'search' => array(),
|
308 |
'filenum' => absint( $_POST['filenum'] )
|
309 |
);
|
@@ -326,6 +404,7 @@ class String_Locator
|
|
326 |
if ( ! isset( $file_data[ $filenum ] ) ) {
|
327 |
wp_send_json_error(
|
328 |
sprintf(
|
|
|
329 |
__( 'The file-number, %d, that was sent could not be found.', 'string-locator' ),
|
330 |
$filenum
|
331 |
)
|
@@ -335,7 +414,8 @@ class String_Locator
|
|
335 |
if ( $this->nearing_execution_limit() ) {
|
336 |
wp_send_json_error(
|
337 |
sprintf(
|
338 |
-
|
|
|
339 |
$this->max_execution_time,
|
340 |
$this->nearing_execution_limit()
|
341 |
)
|
@@ -344,7 +424,8 @@ class String_Locator
|
|
344 |
if ( $this->nearing_memory_limit() ) {
|
345 |
wp_send_json_error(
|
346 |
sprintf(
|
347 |
-
|
|
|
348 |
$this->nearing_memory_limit(),
|
349 |
$this->max_memory_consumption
|
350 |
)
|
@@ -367,9 +448,10 @@ class String_Locator
|
|
367 |
}
|
368 |
}
|
369 |
|
370 |
-
while ( ! $this->nearing_execution_limit() && ! $this->nearing_memory_limit() && isset( $file_data[ $filenum ]) ) {
|
371 |
-
$filenum
|
372 |
-
$
|
|
|
373 |
|
374 |
$next_chunk = ( ceil( ( $next_file ) / $files_per_chunk ) - 1 );
|
375 |
$chunk = ( ceil( $filenum / $files_per_chunk ) - 1 );
|
@@ -393,21 +475,21 @@ class String_Locator
|
|
393 |
* Check the file type, if it's an unsupported type, we skip it
|
394 |
*/
|
395 |
$file_type = explode( '.', $file_name );
|
396 |
-
$file_type = end( $file_type );
|
397 |
-
|
398 |
-
if ( in_array( $file_type, $this->bad_file_types ) ) {
|
399 |
-
continue;
|
400 |
-
}
|
401 |
|
402 |
/*
|
403 |
-
* Scan the file and look for our string
|
404 |
*/
|
405 |
-
|
|
|
|
|
406 |
|
407 |
$response['last_file'] = $file_data[ $filenum ];
|
408 |
$response['filenum'] = $filenum;
|
409 |
$response['filename'] = $file_name;
|
410 |
-
|
|
|
|
|
411 |
|
412 |
if ( $next_chunk != $chunk ) {
|
413 |
$file_data = unserialize( get_option( 'string-locator-search-files-' . $next_chunk ) );
|
@@ -421,22 +503,24 @@ class String_Locator
|
|
421 |
update_option( 'string-locator-search-history', serialize( $history ), false );
|
422 |
}
|
423 |
|
424 |
-
$_POST['filenum']++;
|
425 |
}
|
426 |
|
427 |
wp_send_json_success( $response );
|
428 |
}
|
429 |
|
430 |
/**
|
431 |
-
* Clean up our options used to help during the search
|
432 |
*
|
433 |
-
* @return
|
434 |
*/
|
435 |
function ajax_clean_search() {
|
436 |
-
if ( ! check_ajax_referer( 'string-locator-search', 'nonce', false ) ) {
|
|
|
|
|
437 |
|
438 |
$scan_data = unserialize( get_option( 'string-locator-search-overview' ) );
|
439 |
-
for( $i = 0; $i < $scan_data->chunks; $i++ ) {
|
440 |
delete_option( 'string-locator-search-files-' . $i );
|
441 |
}
|
442 |
|
@@ -444,9 +528,9 @@ class String_Locator
|
|
444 |
}
|
445 |
|
446 |
/**
|
447 |
-
* Create a table row for insertion into the search results list
|
448 |
*
|
449 |
-
* @param array|object $item The table row item
|
450 |
*
|
451 |
* @return string
|
452 |
*/
|
@@ -469,10 +553,10 @@ class String_Locator
|
|
469 |
}
|
470 |
|
471 |
/**
|
472 |
-
* Create a full table populated with the supplied items
|
473 |
*
|
474 |
-
* @param array $items An array of table rows
|
475 |
-
* @param array $table_class An array of items to append to the table class along with the defaults
|
476 |
*
|
477 |
* @return string
|
478 |
*/
|
@@ -497,7 +581,7 @@ class String_Locator
|
|
497 |
);
|
498 |
|
499 |
$table_rows = array();
|
500 |
-
foreach( $items AS $item ) {
|
501 |
$table_rows[] = self::prepare_table_row( $item );
|
502 |
}
|
503 |
|
@@ -513,10 +597,10 @@ class String_Locator
|
|
513 |
}
|
514 |
|
515 |
/**
|
516 |
-
* Create an admin edit link for the supplied path
|
517 |
*
|
518 |
-
* @param string $path
|
519 |
-
* @param int $line
|
520 |
*
|
521 |
* @return string
|
522 |
*/
|
@@ -525,8 +609,8 @@ class String_Locator
|
|
525 |
$file_slug = '';
|
526 |
$content_path = str_replace( '\\', '/', WP_CONTENT_DIR );
|
527 |
|
528 |
-
$path
|
529 |
-
$paths
|
530 |
|
531 |
$url_args = array(
|
532 |
'page=string-locator',
|
@@ -535,11 +619,11 @@ class String_Locator
|
|
535 |
|
536 |
switch ( true ) {
|
537 |
case ( in_array( 'wp-content', $paths ) && in_array( 'plugins', $paths ) ) :
|
538 |
-
$file_type
|
539 |
$content_path .= '/plugins/';
|
540 |
break;
|
541 |
case ( in_array( 'wp-content', $paths ) && in_array( 'themes', $paths ) ) :
|
542 |
-
$file_type
|
543 |
$content_path .= '/themes/';
|
544 |
break;
|
545 |
}
|
@@ -562,9 +646,9 @@ class String_Locator
|
|
562 |
}
|
563 |
|
564 |
/**
|
565 |
-
* Parse the search option to determine what kind of search we are performing and what directory to start in
|
566 |
*
|
567 |
-
* @param $option
|
568 |
*
|
569 |
* @return bool|object
|
570 |
*/
|
@@ -589,6 +673,10 @@ class String_Locator
|
|
589 |
$data['path'] = WP_CONTENT_DIR . '/plugins/';
|
590 |
$data['type'] = 'plugin';
|
591 |
break;
|
|
|
|
|
|
|
|
|
592 |
case ( strlen( $option ) > 3 && 'p-' == substr( $option, 0, 2 ) ):
|
593 |
$slug = explode( '/', substr( $option, 2 ) );
|
594 |
|
@@ -614,9 +702,10 @@ class String_Locator
|
|
614 |
}
|
615 |
|
616 |
/**
|
617 |
-
* Check if a file path is valid for editing
|
|
|
|
|
618 |
*
|
619 |
-
* @param string $path Path to file
|
620 |
* @return bool
|
621 |
*/
|
622 |
function is_valid_location( $path ) {
|
@@ -638,7 +727,9 @@ class String_Locator
|
|
638 |
}
|
639 |
|
640 |
/**
|
641 |
-
* Set the text domain for translated plugin content
|
|
|
|
|
642 |
*/
|
643 |
function load_i18n() {
|
644 |
$i18n_dir = 'string-locator/languages/';
|
@@ -646,7 +737,9 @@ class String_Locator
|
|
646 |
}
|
647 |
|
648 |
/**
|
649 |
-
* Load up JavaScript and CSS for our plugin on the appropriate admin pages
|
|
|
|
|
650 |
*/
|
651 |
function admin_enqueue_scripts( $hook ) {
|
652 |
// Break out early if we are not on a String Locator page
|
@@ -664,10 +757,10 @@ class String_Locator
|
|
664 |
*/
|
665 |
wp_register_script( 'string-locator-search', plugin_dir_url( __FILE__ ) . '/resources/js/string-locator-search.js', array( 'jquery' ), $this->version );
|
666 |
|
667 |
-
if ( isset( $_GET['edit-file'] )) {
|
668 |
$filename = explode( '.', $_GET['edit-file'] );
|
669 |
-
$filext
|
670 |
-
switch( $filext ) {
|
671 |
case 'js':
|
672 |
$this->string_locator_language = 'javascript';
|
673 |
break;
|
@@ -742,6 +835,7 @@ class String_Locator
|
|
742 |
wp_localize_script( 'string-locator-search', 'string_locator', array(
|
743 |
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
744 |
'search_nonce' => wp_create_nonce( 'string-locator-search' ),
|
|
|
745 |
'saving_results_string' => __( 'Saving search results…', 'string-locator' ),
|
746 |
'search_preparing' => __( 'Preparing search…', 'string-locator' ),
|
747 |
'search_started' => __( 'Preparations completed, search started…', 'string-locator' ),
|
@@ -752,10 +846,11 @@ class String_Locator
|
|
752 |
}
|
753 |
|
754 |
/**
|
755 |
-
* Add our plugin to the 'Tools' menu
|
|
|
|
|
756 |
*/
|
757 |
-
function populate_menu()
|
758 |
-
{
|
759 |
if ( is_multisite() ) {
|
760 |
return;
|
761 |
}
|
@@ -769,22 +864,27 @@ class String_Locator
|
|
769 |
add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $menu_slug, $function );
|
770 |
}
|
771 |
|
772 |
-
|
773 |
-
|
774 |
-
|
775 |
-
|
776 |
-
|
777 |
-
|
778 |
-
$
|
|
|
|
|
|
|
|
|
779 |
|
780 |
add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function, 'dashicons-edit' );
|
781 |
}
|
782 |
|
783 |
/**
|
784 |
-
* Function for including the actual plugin Admin UI page
|
|
|
|
|
785 |
*/
|
786 |
-
function options_page()
|
787 |
-
{
|
788 |
/**
|
789 |
* Don't load anything if the user can't edit themes any way
|
790 |
*/
|
@@ -800,27 +900,29 @@ class String_Locator
|
|
800 |
*/
|
801 |
if ( isset( $_GET['string-locator-path'] ) && $this->is_valid_location( $_GET['string-locator-path'] ) ) {
|
802 |
include_once( dirname( __FILE__ ) . '/editor.php' );
|
803 |
-
}
|
804 |
-
else {
|
805 |
include_once( dirname( __FILE__ ) . '/options.php' );
|
806 |
}
|
807 |
}
|
808 |
|
809 |
/**
|
810 |
-
*
|
811 |
-
*
|
812 |
-
* @param string $
|
|
|
|
|
|
|
813 |
* @return array
|
814 |
*/
|
815 |
function SmartScan( $start, $end, $string ) {
|
816 |
$opened = array();
|
817 |
|
818 |
$lines = explode( "\n", $string );
|
819 |
-
for ( $i = 0; $i < count( $lines ); $i++ ) {
|
820 |
-
if ( stristr( $lines[$i], $start ) ) {
|
821 |
$opened[] = $i;
|
822 |
}
|
823 |
-
if ( stristr( $lines[$i], $end ) ) {
|
824 |
array_pop( $opened );
|
825 |
}
|
826 |
}
|
@@ -829,25 +931,29 @@ class String_Locator
|
|
829 |
}
|
830 |
|
831 |
/**
|
832 |
-
* Handler for storing the content of the code editor
|
833 |
-
*
|
|
|
|
|
|
|
834 |
*/
|
835 |
function editor_save() {
|
836 |
if ( isset( $_POST['string-locator-editor-content'] ) && check_admin_referer( 'string-locator-edit_' . $_GET['edit-file'] ) && current_user_can( 'edit_themes' ) ) {
|
837 |
|
838 |
if ( $this->is_valid_location( $_GET['string-locator-path'] ) ) {
|
839 |
-
$path
|
840 |
$content = stripslashes( $_POST['string-locator-editor-content'] );
|
841 |
|
842 |
/**
|
843 |
* Send an error notice if the file isn't writable
|
844 |
*/
|
845 |
if ( ! is_writeable( $path ) ) {
|
846 |
-
$this->notice[]
|
847 |
'type' => 'error',
|
848 |
'message' => __( 'The file could not be written to, please check file permissions or edit it manually.', 'string-locator' )
|
849 |
);
|
850 |
$this->failed_edit = true;
|
|
|
851 |
return;
|
852 |
}
|
853 |
|
@@ -855,37 +961,37 @@ class String_Locator
|
|
855 |
* If enabled, run the Smart-Scan on the content before saving it
|
856 |
*/
|
857 |
if ( isset( $_POST['string-locator-smart-edit'] ) ) {
|
858 |
-
$open_brace
|
859 |
$close_brace = substr_count( $content, '}' );
|
860 |
if ( $open_brace != $close_brace ) {
|
861 |
$this->failed_edit = true;
|
862 |
|
863 |
$opened = $this->SmartScan( '{', '}', $content );
|
864 |
|
865 |
-
foreach( $opened AS $line ) {
|
866 |
$this->notice[] = array(
|
867 |
'type' => 'error',
|
868 |
'message' => sprintf(
|
869 |
__( 'There is an inconsistency in the opening and closing braces, { and }, of your file on line %s', 'string-locator' ),
|
870 |
-
'<a href="#" class="string-locator-edit-goto" data-goto-line="' . ( $line + 1 ). '">' . ( $line + 1 ) . '</a>'
|
871 |
)
|
872 |
);
|
873 |
}
|
874 |
}
|
875 |
|
876 |
-
$open_bracket
|
877 |
$close_bracket = substr_count( $content, ']' );
|
878 |
if ( $open_bracket != $close_bracket ) {
|
879 |
$this->failed_edit = true;
|
880 |
|
881 |
$opened = $this->SmartScan( '[', ']', $content );
|
882 |
|
883 |
-
foreach( $opened AS $line ) {
|
884 |
$this->notice[] = array(
|
885 |
'type' => 'error',
|
886 |
'message' => sprintf(
|
887 |
__( 'There is an inconsistency in the opening and closing braces, [ and ], of your file on line %s', 'string-locator' ),
|
888 |
-
'<a href="#" class="string-locator-edit-goto" data-goto-line="' . ( $line + 1 ). '">' . ( $line + 1 ) . '</a>'
|
889 |
)
|
890 |
);
|
891 |
}
|
@@ -898,12 +1004,12 @@ class String_Locator
|
|
898 |
|
899 |
$opened = $this->SmartScan( '(', ')', $content );
|
900 |
|
901 |
-
foreach( $opened AS $line ) {
|
902 |
$this->notice[] = array(
|
903 |
'type' => 'error',
|
904 |
'message' => sprintf(
|
905 |
__( 'There is an inconsistency in the opening and closing braces, ( and ), of your file on line %s', 'string-locator' ),
|
906 |
-
'<a href="#" class="string-locator-edit-goto" data-goto-line="' . ( $line + 1 ). '">' . ( $line + 1 ) . '</a>'
|
907 |
)
|
908 |
);
|
909 |
}
|
@@ -939,8 +1045,7 @@ class String_Locator
|
|
939 |
'type' => 'error',
|
940 |
'message' => __( 'A 500 server error was detected on your site after updating your file. We have restored the previous version of the file for you.', 'string-locator' )
|
941 |
);
|
942 |
-
}
|
943 |
-
else {
|
944 |
$this->notice[] = array(
|
945 |
'type' => 'updated',
|
946 |
'message' => __( 'The file has been saved', 'string-locator' )
|
@@ -950,6 +1055,13 @@ class String_Locator
|
|
950 |
}
|
951 |
}
|
952 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
953 |
private function create_child_theme( $theme ) {
|
954 |
$child_theme = sprintf( '%s/%s-child', get_theme_root(), $theme );
|
955 |
mkdir( $child_theme );
|
@@ -961,11 +1073,13 @@ class String_Locator
|
|
961 |
}
|
962 |
|
963 |
/**
|
964 |
-
* When editing a file, this is where we write all the new content
|
965 |
-
* We will break early if the user isn't allowed to edit files
|
|
|
|
|
|
|
966 |
*
|
967 |
-
* @
|
968 |
-
* @param string $content - The content to write to the file
|
969 |
*/
|
970 |
private function write_file( $path, $content ) {
|
971 |
if ( ! current_user_can( 'edit_themes' ) ) {
|
@@ -973,7 +1087,7 @@ class String_Locator
|
|
973 |
}
|
974 |
|
975 |
if ( apply_filters( 'string-locator-filter-closing-php-tags', true ) ) {
|
976 |
-
$content = preg_replace( "/\?>$/si", '', trim( $content ), -1, $replaced_strings );
|
977 |
|
978 |
if ( $replaced_strings >= 1 ) {
|
979 |
$this->notice[] = array(
|
@@ -987,7 +1101,7 @@ class String_Locator
|
|
987 |
$lines = explode( "\n", str_replace( array( "\r\n", "\r" ), "\n", $content ) );
|
988 |
$total_lines = count( $lines );
|
989 |
|
990 |
-
for( $i = 0; $i < $total_lines; $i++ ) {
|
991 |
$write_line = $lines[ $i ];
|
992 |
|
993 |
if ( ( $i + 1 ) < $total_lines ) {
|
@@ -1001,11 +1115,13 @@ class String_Locator
|
|
1001 |
}
|
1002 |
|
1003 |
/**
|
1004 |
-
* Hook the admin notices and loop over any notices we've registered in the plugin
|
|
|
|
|
1005 |
*/
|
1006 |
function admin_notice() {
|
1007 |
if ( ! empty( $this->notice ) ) {
|
1008 |
-
foreach( $this->notice AS $note ) {
|
1009 |
printf(
|
1010 |
'<div class="%s"><p>%s</p></div>',
|
1011 |
esc_attr( $note['type'] ),
|
@@ -1016,14 +1132,14 @@ class String_Locator
|
|
1016 |
}
|
1017 |
|
1018 |
/**
|
1019 |
-
* Scan through an individual file to look for occurrences of £string
|
1020 |
*
|
1021 |
-
* @param string
|
1022 |
-
* @param string
|
1023 |
-
* @param mixed
|
1024 |
-
* @param string
|
1025 |
-
* @param string
|
1026 |
-
* @param boolean $regex
|
1027 |
*
|
1028 |
* @return mixed
|
1029 |
*/
|
@@ -1031,16 +1147,15 @@ class String_Locator
|
|
1031 |
if ( empty( $string ) || ! is_file( $filename ) ) {
|
1032 |
return false;
|
1033 |
}
|
1034 |
-
$output
|
1035 |
-
$linenum
|
1036 |
$match_count = 0;
|
1037 |
|
1038 |
if ( ! is_object( $location ) ) {
|
1039 |
-
$path
|
1040 |
$location = explode( DIRECTORY_SEPARATOR, $location );
|
1041 |
-
$file
|
1042 |
-
}
|
1043 |
-
else {
|
1044 |
$path = $location->getPathname();
|
1045 |
$file = $location->getFilename();
|
1046 |
}
|
@@ -1049,8 +1164,12 @@ class String_Locator
|
|
1049 |
* Check if the filename matches our search pattern
|
1050 |
*/
|
1051 |
if ( stristr( $file, $string ) || ( $regex && preg_match( $string, $file ) ) ) {
|
1052 |
-
$relativepath = str_replace( array( ABSPATH, '\\', '/' ), array(
|
1053 |
-
|
|
|
|
|
|
|
|
|
1054 |
|
1055 |
$editurl = $this->create_edit_link( $path, $linenum );
|
1056 |
|
@@ -1075,31 +1194,32 @@ class String_Locator
|
|
1075 |
}
|
1076 |
|
1077 |
$readfile = @fopen( $filename, "r" );
|
1078 |
-
if ( $readfile )
|
1079 |
-
|
1080 |
-
while ( ( $readline = fgets( $readfile ) ) !== false )
|
1081 |
-
{
|
1082 |
$string_preview_is_cut = false;
|
1083 |
-
$linenum++;
|
1084 |
/**
|
1085 |
* If our string is found in this line, output the line number and other data
|
1086 |
*/
|
1087 |
-
if ( ( ! $regex && stristr( $readline, $string ) ) || ( $regex && preg_match( $string, $readline ) ) )
|
1088 |
-
{
|
1089 |
/**
|
1090 |
* Prepare the visual path for the end user
|
1091 |
* Removes path leading up to WordPress root and ensures consistent directory separators
|
1092 |
*/
|
1093 |
-
$relativepath = str_replace( array( ABSPATH, '\\', '/' ), array(
|
1094 |
-
|
|
|
|
|
|
|
|
|
1095 |
|
1096 |
/**
|
1097 |
* Create the URL to take the user to the editor
|
1098 |
*/
|
1099 |
$editurl = $this->create_edit_link( $path, $linenum );
|
1100 |
|
1101 |
-
$string_preview
|
1102 |
-
if ( strlen( $string_preview ) >
|
1103 |
$string_location = strpos( $string_preview, $string );
|
1104 |
|
1105 |
$string_location_start = $string_location - $this->excerpt_length;
|
@@ -1107,19 +1227,18 @@ class String_Locator
|
|
1107 |
$string_location_start = 0;
|
1108 |
}
|
1109 |
|
1110 |
-
$string_location_end =
|
1111 |
if ( $string_location_end > strlen( $string_preview ) ) {
|
1112 |
$string_location_end = strlen( $string_preview );
|
1113 |
}
|
1114 |
|
1115 |
-
$string_preview
|
1116 |
$string_preview_is_cut = true;
|
1117 |
}
|
1118 |
|
1119 |
if ( $regex ) {
|
1120 |
$string_preview = preg_replace( preg_replace( '/\/(.+)\//', '/($1)/', $string ), '<strong>$1</strong>', esc_html( $string_preview ) );
|
1121 |
-
}
|
1122 |
-
else {
|
1123 |
$string_preview = str_ireplace( $string, '<strong>' . $string . '</strong>', esc_html( $string_preview ) );
|
1124 |
}
|
1125 |
if ( $string_preview_is_cut ) {
|
@@ -1148,8 +1267,7 @@ class String_Locator
|
|
1148 |
}
|
1149 |
|
1150 |
fclose( $readfile );
|
1151 |
-
}
|
1152 |
-
else {
|
1153 |
/**
|
1154 |
* The file was unreadable, give the user a friendly notification
|
1155 |
*/
|
3 |
* Plugin Name: String Locator
|
4 |
* Plugin URI: http://www.clorith.net/wordpress-string-locator/
|
5 |
* Description: Scan through theme and plugin files looking for text strings
|
6 |
+
* Version: 2.2.0
|
7 |
* Author: Clorith
|
8 |
* Author URI: http://www.clorith.net
|
9 |
* Text Domain: string-locator
|
28 |
/**
|
29 |
* Class String_Locator
|
30 |
*/
|
31 |
+
class String_Locator {
|
|
|
32 |
/**
|
33 |
+
* @var string $string_locator_language The code language used for the editing page.
|
34 |
+
* @var string $version String Locator version number.
|
35 |
+
* @var array $notice An array containing all notices to display.
|
36 |
+
* @var bool $failed_edit Has there been a failed edit.
|
37 |
+
* @var string $plugin_url The URL to the plugins directory.
|
38 |
+
* @var string $path_to_use The path to the currently editable file.
|
39 |
+
* @var array $bad_http_codes An array of HTTP status codes that will trigger the rollback feature.
|
40 |
+
* @var array $bad_file_types An array of file extensions that will be ignored by the scanner.
|
41 |
+
* @var int $excerpt_length The length of the excerpt from the line containing a match.
|
42 |
+
* @var int|null $max_execution_time The server-configured max time a script can run.
|
43 |
+
* @var int $start_execution_time The current time when our script started executing.
|
44 |
+
* @var int $max_memory_consumption The server-configured max amount of memory a script can use.
|
45 |
*/
|
46 |
+
public $string_locator_language = '';
|
47 |
+
public $version = '2.2.0';
|
48 |
+
public $notice = array();
|
49 |
+
public $failed_edit = false;
|
50 |
+
private $plugin_url = '';
|
51 |
+
private $path_to_use = '';
|
52 |
+
private $bad_http_codes = array( '500' );
|
53 |
+
private $bad_file_types = array( 'rar', '7z', 'zip', 'tar', 'gz', 'jpg', 'jpeg', 'png', 'gif', 'mp3', 'mp4', 'avi', 'wmv' );
|
54 |
+
private $excerpt_length = 25;
|
55 |
+
private $max_execution_time = null;
|
56 |
+
private $start_execution_timer = 0;
|
57 |
+
private $max_memory_consumption = 0;
|
58 |
|
59 |
/**
|
60 |
* Construct the plugin
|
61 |
*/
|
62 |
+
function __construct() {
|
63 |
+
$this->init();
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* The plugin initialization, ready as a stand alone function so it can be instantiated in other
|
68 |
+
* scenarios as well.
|
69 |
+
*
|
70 |
+
* @since 2.2.0
|
71 |
+
*
|
72 |
+
* @return void
|
73 |
+
*/
|
74 |
+
public function init() {
|
75 |
/**
|
76 |
* Define class variables requiring expressions
|
77 |
*/
|
79 |
$this->path_to_use = ( is_multisite() ? 'network/admin.php' : 'tools.php' );
|
80 |
$this->excerpt_length = apply_filters( 'string_locator_excerpt_length', 25 );
|
81 |
|
82 |
+
$this->max_execution_time = absint( ini_get( 'max_execution_time' ) );
|
83 |
$this->start_execution_timer = microtime( true );
|
84 |
|
85 |
+
if ( $this->max_execution_time > 30 ) {
|
86 |
+
$this->max_execution_time = 30;
|
87 |
+
}
|
88 |
+
|
89 |
$this->set_memory_limit();
|
90 |
|
91 |
add_action( 'admin_menu', array( $this, 'populate_menu' ) );
|
106 |
}
|
107 |
|
108 |
/**
|
109 |
+
* Sets up the memory limit variables.
|
110 |
*
|
111 |
* @since 2.0.0
|
112 |
*
|
129 |
}
|
130 |
|
131 |
/**
|
132 |
+
* Add a donation link to the plugins page.
|
133 |
+
*
|
134 |
+
* @param array $meta An array of meta links for this plugin.
|
135 |
+
* @param string $plugin_file The main plugin file name, used to identify our own plugin.
|
136 |
*
|
137 |
* @return array
|
138 |
*/
|
148 |
}
|
149 |
|
150 |
/**
|
151 |
+
* Create a set of drop-down options for picking one of the available themes.
|
152 |
*
|
153 |
+
* @param string $current The current selection option to match against.
|
154 |
*
|
155 |
* @return string
|
156 |
*/
|
164 |
|
165 |
$string_locate_themes = wp_get_themes();
|
166 |
|
167 |
+
foreach ( $string_locate_themes AS $string_locate_theme_slug => $string_locate_theme ) {
|
168 |
$string_locate_theme_data = wp_get_theme( $string_locate_theme_slug );
|
169 |
+
$string_locate_value = 't-' . $string_locate_theme_slug;
|
170 |
|
171 |
$options .= sprintf(
|
172 |
'<option value="%s" %s>%s</option>',
|
180 |
}
|
181 |
|
182 |
/**
|
183 |
+
* Create a set of drop-down options for picking one of the available plugins.
|
184 |
*
|
185 |
+
* @param string $current The current selection option to match against.
|
186 |
*
|
187 |
* @return string
|
188 |
*/
|
196 |
|
197 |
$string_locate_plugins = get_plugins();
|
198 |
|
199 |
+
foreach ( $string_locate_plugins AS $string_locate_plugin_path => $string_locate_plugin ) {
|
|
|
200 |
$string_locate_value = 'p-' . $string_locate_plugin_path;
|
201 |
|
202 |
$options .= sprintf(
|
211 |
}
|
212 |
|
213 |
/**
|
214 |
+
* Create a set of drop-down options for picking one of the available must-use plugins.
|
215 |
+
*
|
216 |
+
* @param string $current The current selection option to match against.
|
217 |
+
*
|
218 |
+
* @return string
|
219 |
+
*/
|
220 |
+
public static function get_mu_plugins_options( $current = null ) {
|
221 |
+
$options = sprintf(
|
222 |
+
'<option value="%s" %s>— %s —</option>',
|
223 |
+
'mup--',
|
224 |
+
( 'mup--' == $current ? 'selected="selected"' : '' ),
|
225 |
+
esc_html__( 'All must-use plugins', 'string-locator' )
|
226 |
+
);
|
227 |
+
|
228 |
+
$string_locate_plugins = get_mu_plugins();
|
229 |
+
|
230 |
+
foreach ( $string_locate_plugins AS $string_locate_plugin_path => $string_locate_plugin ) {
|
231 |
+
$string_locate_value = 'mup-' . $string_locate_plugin_path;
|
232 |
+
|
233 |
+
$options .= sprintf(
|
234 |
+
'<option value="%s" %s>%s</option>',
|
235 |
+
$string_locate_value,
|
236 |
+
( $current == $string_locate_value ? 'selected="selected"' : '' ),
|
237 |
+
$string_locate_plugin['Name']
|
238 |
+
);
|
239 |
+
}
|
240 |
+
|
241 |
+
return $options;
|
242 |
+
}
|
243 |
+
|
244 |
+
/**
|
245 |
+
* Check if there are Must-Use plugins available on this WordPress install.
|
246 |
+
*
|
247 |
+
* @since 2.2.0
|
248 |
+
*
|
249 |
+
* @return bool
|
250 |
+
*/
|
251 |
+
public static function has_mu_plugins() {
|
252 |
+
$mu_plugin_count = get_mu_plugins();
|
253 |
+
|
254 |
+
if ( count( $mu_plugin_count ) >= 1 ) {
|
255 |
+
return true;
|
256 |
+
}
|
257 |
+
|
258 |
+
return false;
|
259 |
+
}
|
260 |
+
|
261 |
+
/**
|
262 |
+
* Handles the AJAX request to prepare the search hierarchy.
|
263 |
*
|
264 |
+
* @return void
|
265 |
*/
|
266 |
function ajax_get_directory_structure() {
|
267 |
+
if ( ! check_ajax_referer( 'string-locator-search', 'nonce', false ) ) {
|
268 |
+
wp_send_json_error( __( 'Authentication failed', 'string-locator' ) );
|
269 |
+
}
|
270 |
|
271 |
$scan_path = $this->prepare_scan_path( $_POST['directory'] );
|
272 |
if ( is_file( $scan_path->path ) ) {
|
273 |
$files = array( $scan_path->path );
|
274 |
+
} else {
|
|
|
275 |
$files = $this->ajax_scan_path( $scan_path->path );
|
276 |
}
|
277 |
|
300 |
update_option( 'string-locator-search-overview', serialize( $store ), true );
|
301 |
update_option( 'string-locator-search-history', serialize( array() ) );
|
302 |
|
303 |
+
foreach ( $file_chunks AS $count => $file_chunk ) {
|
304 |
update_option( 'string-locator-search-files-' . $count, serialize( $file_chunk ) );
|
305 |
}
|
306 |
|
315 |
* @return bool
|
316 |
*/
|
317 |
function nearing_execution_limit() {
|
318 |
+
// Max execution time is 0 or -1 (infinite) in server config
|
319 |
+
if ( 0 === $this->max_execution_time || - 1 === $this->max_execution_time ) {
|
320 |
return false;
|
321 |
}
|
322 |
|
326 |
if ( $execution_time >= $this->max_execution_time ) {
|
327 |
return $execution_time;
|
328 |
}
|
329 |
+
|
330 |
return false;
|
331 |
}
|
332 |
|
338 |
* @return bool
|
339 |
*/
|
340 |
function nearing_memory_limit() {
|
341 |
+
// Check if the memory limit is set t o0 or -1 (infinite) in server config
|
342 |
+
if ( 0 === $this->max_memory_consumption || - 1 === $this->max_memory_consumption ) {
|
343 |
+
return false;
|
344 |
+
}
|
345 |
+
|
346 |
// We give our selves a 256k memory buffer, as we need to close off the script properly as well
|
347 |
$built_in_buffer = apply_filters( 'string-locator-extra-memory-buffer', 256000 );
|
348 |
+
$memory_use = ( memory_get_usage( true ) + $built_in_buffer );
|
349 |
|
350 |
if ( $memory_use >= $this->max_memory_consumption ) {
|
351 |
return $memory_use;
|
352 |
}
|
353 |
+
|
354 |
return false;
|
355 |
}
|
356 |
|
357 |
public static function absbool( $value ) {
|
358 |
if ( is_bool( $value ) ) {
|
359 |
$bool = $value;
|
360 |
+
} else {
|
|
|
361 |
if ( 'false' == $value ) {
|
362 |
$bool = false;
|
363 |
+
} else {
|
|
|
364 |
$bool = true;
|
365 |
}
|
366 |
}
|
369 |
}
|
370 |
|
371 |
/**
|
372 |
+
* Search an individual file supplied via AJAX.
|
373 |
*
|
374 |
* @since 1.9.0
|
375 |
*
|
376 |
+
* @return void
|
377 |
*/
|
378 |
function ajax_file_search() {
|
379 |
+
if ( ! check_ajax_referer( 'string-locator-search', 'nonce', false ) ) {
|
380 |
+
wp_send_json_error( __( 'Authentication failed', 'string-locator' ) );
|
381 |
+
}
|
382 |
|
383 |
$files_per_chunk = apply_filters( 'string-locator-files-per-array', 500 );
|
384 |
+
$response = array(
|
385 |
'search' => array(),
|
386 |
'filenum' => absint( $_POST['filenum'] )
|
387 |
);
|
404 |
if ( ! isset( $file_data[ $filenum ] ) ) {
|
405 |
wp_send_json_error(
|
406 |
sprintf(
|
407 |
+
/* translators: %d: The numbered reference to a file being searched. */
|
408 |
__( 'The file-number, %d, that was sent could not be found.', 'string-locator' ),
|
409 |
$filenum
|
410 |
)
|
414 |
if ( $this->nearing_execution_limit() ) {
|
415 |
wp_send_json_error(
|
416 |
sprintf(
|
417 |
+
/* translators: %1$d: The time a PHP file can run, as defined by the server configuration. %2$d: The amount of time used by the PHP file so far. */
|
418 |
+
__( 'The maximum time your server allows a script to run (%1$d) is too low for the plugin to run as intended, at startup %2$d seconds have passed', 'string-locator' ),
|
419 |
$this->max_execution_time,
|
420 |
$this->nearing_execution_limit()
|
421 |
)
|
424 |
if ( $this->nearing_memory_limit() ) {
|
425 |
wp_send_json_error(
|
426 |
sprintf(
|
427 |
+
/* translators: %1$d: Current amount of used system memory resources. %2$d: The maximum available system memory. */
|
428 |
+
__( 'The memory limit is about to be exceeded before the search has started, this could be an early indicator that your site may soon struggle as well, unfortunately this means the plugin is unable to perform any searches. Current memory consumption: %1$d of %2$d bytes', 'string-locator' ),
|
429 |
$this->nearing_memory_limit(),
|
430 |
$this->max_memory_consumption
|
431 |
)
|
448 |
}
|
449 |
}
|
450 |
|
451 |
+
while ( ! $this->nearing_execution_limit() && ! $this->nearing_memory_limit() && isset( $file_data[ $filenum ] ) ) {
|
452 |
+
$filenum = absint( $_POST['filenum'] );
|
453 |
+
$search_results = null;
|
454 |
+
$next_file = $filenum + 1;
|
455 |
|
456 |
$next_chunk = ( ceil( ( $next_file ) / $files_per_chunk ) - 1 );
|
457 |
$chunk = ( ceil( $filenum / $files_per_chunk ) - 1 );
|
475 |
* Check the file type, if it's an unsupported type, we skip it
|
476 |
*/
|
477 |
$file_type = explode( '.', $file_name );
|
478 |
+
$file_type = strtolower( end( $file_type ) );
|
|
|
|
|
|
|
|
|
479 |
|
480 |
/*
|
481 |
+
* Scan the file and look for our string, but only if it's an approved file extension
|
482 |
*/
|
483 |
+
if ( ! in_array( $file_type, $this->bad_file_types ) ) {
|
484 |
+
$search_results = $this->scan_file( $file_data[ $filenum ], $scan_data->search, $file_data[ $filenum ], $scan_data->scan_path->type, '', $is_regex );
|
485 |
+
}
|
486 |
|
487 |
$response['last_file'] = $file_data[ $filenum ];
|
488 |
$response['filenum'] = $filenum;
|
489 |
$response['filename'] = $file_name;
|
490 |
+
if ( $search_results ) {
|
491 |
+
$response['search'][] = $search_results;
|
492 |
+
}
|
493 |
|
494 |
if ( $next_chunk != $chunk ) {
|
495 |
$file_data = unserialize( get_option( 'string-locator-search-files-' . $next_chunk ) );
|
503 |
update_option( 'string-locator-search-history', serialize( $history ), false );
|
504 |
}
|
505 |
|
506 |
+
$_POST['filenum'] ++;
|
507 |
}
|
508 |
|
509 |
wp_send_json_success( $response );
|
510 |
}
|
511 |
|
512 |
/**
|
513 |
+
* Clean up our options used to help during the search.
|
514 |
*
|
515 |
+
* @return void
|
516 |
*/
|
517 |
function ajax_clean_search() {
|
518 |
+
if ( ! check_ajax_referer( 'string-locator-search', 'nonce', false ) ) {
|
519 |
+
wp_send_json_error( __( 'Authentication failed', 'string-locator' ) );
|
520 |
+
}
|
521 |
|
522 |
$scan_data = unserialize( get_option( 'string-locator-search-overview' ) );
|
523 |
+
for ( $i = 0; $i < $scan_data->chunks; $i ++ ) {
|
524 |
delete_option( 'string-locator-search-files-' . $i );
|
525 |
}
|
526 |
|
528 |
}
|
529 |
|
530 |
/**
|
531 |
+
* Create a table row for insertion into the search results list.
|
532 |
*
|
533 |
+
* @param array|object $item The table row item.
|
534 |
*
|
535 |
* @return string
|
536 |
*/
|
553 |
}
|
554 |
|
555 |
/**
|
556 |
+
* Create a full table populated with the supplied items.
|
557 |
*
|
558 |
+
* @param array $items An array of table rows.
|
559 |
+
* @param array $table_class An array of items to append to the table class along with the defaults.
|
560 |
*
|
561 |
* @return string
|
562 |
*/
|
581 |
);
|
582 |
|
583 |
$table_rows = array();
|
584 |
+
foreach ( $items AS $item ) {
|
585 |
$table_rows[] = self::prepare_table_row( $item );
|
586 |
}
|
587 |
|
597 |
}
|
598 |
|
599 |
/**
|
600 |
+
* Create an admin edit link for the supplied path.
|
601 |
*
|
602 |
+
* @param string $path Path to the file we'er adding a link for.
|
603 |
+
* @param int $line The line in the file where our search result was found.
|
604 |
*
|
605 |
* @return string
|
606 |
*/
|
609 |
$file_slug = '';
|
610 |
$content_path = str_replace( '\\', '/', WP_CONTENT_DIR );
|
611 |
|
612 |
+
$path = str_replace( '\\', '/', $path );
|
613 |
+
$paths = explode( '/', $path );
|
614 |
|
615 |
$url_args = array(
|
616 |
'page=string-locator',
|
619 |
|
620 |
switch ( true ) {
|
621 |
case ( in_array( 'wp-content', $paths ) && in_array( 'plugins', $paths ) ) :
|
622 |
+
$file_type = 'plugin';
|
623 |
$content_path .= '/plugins/';
|
624 |
break;
|
625 |
case ( in_array( 'wp-content', $paths ) && in_array( 'themes', $paths ) ) :
|
626 |
+
$file_type = 'theme';
|
627 |
$content_path .= '/themes/';
|
628 |
break;
|
629 |
}
|
646 |
}
|
647 |
|
648 |
/**
|
649 |
+
* Parse the search option to determine what kind of search we are performing and what directory to start in.
|
650 |
*
|
651 |
+
* @param string $option The search-type identifier.
|
652 |
*
|
653 |
* @return bool|object
|
654 |
*/
|
673 |
$data['path'] = WP_CONTENT_DIR . '/plugins/';
|
674 |
$data['type'] = 'plugin';
|
675 |
break;
|
676 |
+
case ( 'mup--' == $option ):
|
677 |
+
$data['path'] = WP_CONTENT_DIR . '/mu-plugins/';
|
678 |
+
$data['type'] = 'mu-plugin';
|
679 |
+
break;
|
680 |
case ( strlen( $option ) > 3 && 'p-' == substr( $option, 0, 2 ) ):
|
681 |
$slug = explode( '/', substr( $option, 2 ) );
|
682 |
|
702 |
}
|
703 |
|
704 |
/**
|
705 |
+
* Check if a file path is valid for editing.
|
706 |
+
*
|
707 |
+
* @param string $path Path to file.
|
708 |
*
|
|
|
709 |
* @return bool
|
710 |
*/
|
711 |
function is_valid_location( $path ) {
|
727 |
}
|
728 |
|
729 |
/**
|
730 |
+
* Set the text domain for translated plugin content.
|
731 |
+
*
|
732 |
+
* @return void
|
733 |
*/
|
734 |
function load_i18n() {
|
735 |
$i18n_dir = 'string-locator/languages/';
|
737 |
}
|
738 |
|
739 |
/**
|
740 |
+
* Load up JavaScript and CSS for our plugin on the appropriate admin pages.
|
741 |
+
*
|
742 |
+
* @return void
|
743 |
*/
|
744 |
function admin_enqueue_scripts( $hook ) {
|
745 |
// Break out early if we are not on a String Locator page
|
757 |
*/
|
758 |
wp_register_script( 'string-locator-search', plugin_dir_url( __FILE__ ) . '/resources/js/string-locator-search.js', array( 'jquery' ), $this->version );
|
759 |
|
760 |
+
if ( isset( $_GET['edit-file'] ) ) {
|
761 |
$filename = explode( '.', $_GET['edit-file'] );
|
762 |
+
$filext = end( $filename );
|
763 |
+
switch ( $filext ) {
|
764 |
case 'js':
|
765 |
$this->string_locator_language = 'javascript';
|
766 |
break;
|
835 |
wp_localize_script( 'string-locator-search', 'string_locator', array(
|
836 |
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
837 |
'search_nonce' => wp_create_nonce( 'string-locator-search' ),
|
838 |
+
'search_current_prefix' => __( 'Next file: ', 'string-locator' ),
|
839 |
'saving_results_string' => __( 'Saving search results…', 'string-locator' ),
|
840 |
'search_preparing' => __( 'Preparing search…', 'string-locator' ),
|
841 |
'search_started' => __( 'Preparations completed, search started…', 'string-locator' ),
|
846 |
}
|
847 |
|
848 |
/**
|
849 |
+
* Add our plugin to the 'Tools' menu.
|
850 |
+
*
|
851 |
+
* @return void
|
852 |
*/
|
853 |
+
function populate_menu() {
|
|
|
854 |
if ( is_multisite() ) {
|
855 |
return;
|
856 |
}
|
864 |
add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $menu_slug, $function );
|
865 |
}
|
866 |
|
867 |
+
/**
|
868 |
+
* Add our plugin to the main menu in the Network Admin.
|
869 |
+
*
|
870 |
+
* @return void
|
871 |
+
*/
|
872 |
+
function populate_network_menu() {
|
873 |
+
$page_title = __( 'String Locator', 'string-locator' );
|
874 |
+
$menu_title = __( 'String Locator', 'string-locator' );
|
875 |
+
$capability = 'edit_themes';
|
876 |
+
$menu_slug = 'string-locator';
|
877 |
+
$function = array( $this, 'options_page' );
|
878 |
|
879 |
add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function, 'dashicons-edit' );
|
880 |
}
|
881 |
|
882 |
/**
|
883 |
+
* Function for including the actual plugin Admin UI page.
|
884 |
+
*
|
885 |
+
* @return mixed
|
886 |
*/
|
887 |
+
function options_page() {
|
|
|
888 |
/**
|
889 |
* Don't load anything if the user can't edit themes any way
|
890 |
*/
|
900 |
*/
|
901 |
if ( isset( $_GET['string-locator-path'] ) && $this->is_valid_location( $_GET['string-locator-path'] ) ) {
|
902 |
include_once( dirname( __FILE__ ) . '/editor.php' );
|
903 |
+
} else {
|
|
|
904 |
include_once( dirname( __FILE__ ) . '/options.php' );
|
905 |
}
|
906 |
}
|
907 |
|
908 |
/**
|
909 |
+
* Check for inconsistencies in brackets and similar.
|
910 |
+
*
|
911 |
+
* @param string $start Start delimited.
|
912 |
+
* @param string $end End delimiter.
|
913 |
+
* @param string $string The string to scan.
|
914 |
+
*
|
915 |
* @return array
|
916 |
*/
|
917 |
function SmartScan( $start, $end, $string ) {
|
918 |
$opened = array();
|
919 |
|
920 |
$lines = explode( "\n", $string );
|
921 |
+
for ( $i = 0; $i < count( $lines ); $i ++ ) {
|
922 |
+
if ( stristr( $lines[ $i ], $start ) ) {
|
923 |
$opened[] = $i;
|
924 |
}
|
925 |
+
if ( stristr( $lines[ $i ], $end ) ) {
|
926 |
array_pop( $opened );
|
927 |
}
|
928 |
}
|
931 |
}
|
932 |
|
933 |
/**
|
934 |
+
* Handler for storing the content of the code editor.
|
935 |
+
*
|
936 |
+
* Also runs over the Smart-Scan if enabled.
|
937 |
+
*
|
938 |
+
* @return void
|
939 |
*/
|
940 |
function editor_save() {
|
941 |
if ( isset( $_POST['string-locator-editor-content'] ) && check_admin_referer( 'string-locator-edit_' . $_GET['edit-file'] ) && current_user_can( 'edit_themes' ) ) {
|
942 |
|
943 |
if ( $this->is_valid_location( $_GET['string-locator-path'] ) ) {
|
944 |
+
$path = urldecode( $_GET['string-locator-path'] );
|
945 |
$content = stripslashes( $_POST['string-locator-editor-content'] );
|
946 |
|
947 |
/**
|
948 |
* Send an error notice if the file isn't writable
|
949 |
*/
|
950 |
if ( ! is_writeable( $path ) ) {
|
951 |
+
$this->notice[] = array(
|
952 |
'type' => 'error',
|
953 |
'message' => __( 'The file could not be written to, please check file permissions or edit it manually.', 'string-locator' )
|
954 |
);
|
955 |
$this->failed_edit = true;
|
956 |
+
|
957 |
return;
|
958 |
}
|
959 |
|
961 |
* If enabled, run the Smart-Scan on the content before saving it
|
962 |
*/
|
963 |
if ( isset( $_POST['string-locator-smart-edit'] ) ) {
|
964 |
+
$open_brace = substr_count( $content, '{' );
|
965 |
$close_brace = substr_count( $content, '}' );
|
966 |
if ( $open_brace != $close_brace ) {
|
967 |
$this->failed_edit = true;
|
968 |
|
969 |
$opened = $this->SmartScan( '{', '}', $content );
|
970 |
|
971 |
+
foreach ( $opened AS $line ) {
|
972 |
$this->notice[] = array(
|
973 |
'type' => 'error',
|
974 |
'message' => sprintf(
|
975 |
__( 'There is an inconsistency in the opening and closing braces, { and }, of your file on line %s', 'string-locator' ),
|
976 |
+
'<a href="#" class="string-locator-edit-goto" data-goto-line="' . ( $line + 1 ) . '">' . ( $line + 1 ) . '</a>'
|
977 |
)
|
978 |
);
|
979 |
}
|
980 |
}
|
981 |
|
982 |
+
$open_bracket = substr_count( $content, '[' );
|
983 |
$close_bracket = substr_count( $content, ']' );
|
984 |
if ( $open_bracket != $close_bracket ) {
|
985 |
$this->failed_edit = true;
|
986 |
|
987 |
$opened = $this->SmartScan( '[', ']', $content );
|
988 |
|
989 |
+
foreach ( $opened AS $line ) {
|
990 |
$this->notice[] = array(
|
991 |
'type' => 'error',
|
992 |
'message' => sprintf(
|
993 |
__( 'There is an inconsistency in the opening and closing braces, [ and ], of your file on line %s', 'string-locator' ),
|
994 |
+
'<a href="#" class="string-locator-edit-goto" data-goto-line="' . ( $line + 1 ) . '">' . ( $line + 1 ) . '</a>'
|
995 |
)
|
996 |
);
|
997 |
}
|
1004 |
|
1005 |
$opened = $this->SmartScan( '(', ')', $content );
|
1006 |
|
1007 |
+
foreach ( $opened AS $line ) {
|
1008 |
$this->notice[] = array(
|
1009 |
'type' => 'error',
|
1010 |
'message' => sprintf(
|
1011 |
__( 'There is an inconsistency in the opening and closing braces, ( and ), of your file on line %s', 'string-locator' ),
|
1012 |
+
'<a href="#" class="string-locator-edit-goto" data-goto-line="' . ( $line + 1 ) . '">' . ( $line + 1 ) . '</a>'
|
1013 |
)
|
1014 |
);
|
1015 |
}
|
1045 |
'type' => 'error',
|
1046 |
'message' => __( 'A 500 server error was detected on your site after updating your file. We have restored the previous version of the file for you.', 'string-locator' )
|
1047 |
);
|
1048 |
+
} else {
|
|
|
1049 |
$this->notice[] = array(
|
1050 |
'type' => 'updated',
|
1051 |
'message' => __( 'The file has been saved', 'string-locator' )
|
1055 |
}
|
1056 |
}
|
1057 |
|
1058 |
+
/**
|
1059 |
+
* GCreate a child theme for our edits, instead of overwriting the original files.
|
1060 |
+
*
|
1061 |
+
* @param string $theme Slug of the theme being edited.
|
1062 |
+
*
|
1063 |
+
* @return string
|
1064 |
+
*/
|
1065 |
private function create_child_theme( $theme ) {
|
1066 |
$child_theme = sprintf( '%s/%s-child', get_theme_root(), $theme );
|
1067 |
mkdir( $child_theme );
|
1073 |
}
|
1074 |
|
1075 |
/**
|
1076 |
+
* When editing a file, this is where we write all the new content.
|
1077 |
+
* We will break early if the user isn't allowed to edit files.
|
1078 |
+
*
|
1079 |
+
* @param string $path The path to the file.
|
1080 |
+
* @param string $content The content to write to the file.
|
1081 |
*
|
1082 |
+
* @return void
|
|
|
1083 |
*/
|
1084 |
private function write_file( $path, $content ) {
|
1085 |
if ( ! current_user_can( 'edit_themes' ) ) {
|
1087 |
}
|
1088 |
|
1089 |
if ( apply_filters( 'string-locator-filter-closing-php-tags', true ) ) {
|
1090 |
+
$content = preg_replace( "/\?>$/si", '', trim( $content ), - 1, $replaced_strings );
|
1091 |
|
1092 |
if ( $replaced_strings >= 1 ) {
|
1093 |
$this->notice[] = array(
|
1101 |
$lines = explode( "\n", str_replace( array( "\r\n", "\r" ), "\n", $content ) );
|
1102 |
$total_lines = count( $lines );
|
1103 |
|
1104 |
+
for ( $i = 0; $i < $total_lines; $i ++ ) {
|
1105 |
$write_line = $lines[ $i ];
|
1106 |
|
1107 |
if ( ( $i + 1 ) < $total_lines ) {
|
1115 |
}
|
1116 |
|
1117 |
/**
|
1118 |
+
* Hook the admin notices and loop over any notices we've registered in the plugin.
|
1119 |
+
*
|
1120 |
+
* @return void
|
1121 |
*/
|
1122 |
function admin_notice() {
|
1123 |
if ( ! empty( $this->notice ) ) {
|
1124 |
+
foreach ( $this->notice AS $note ) {
|
1125 |
printf(
|
1126 |
'<div class="%s"><p>%s</p></div>',
|
1127 |
esc_attr( $note['type'] ),
|
1132 |
}
|
1133 |
|
1134 |
/**
|
1135 |
+
* Scan through an individual file to look for occurrences of £string.
|
1136 |
*
|
1137 |
+
* @param string $filename The path to the file.
|
1138 |
+
* @param string $string The search string.
|
1139 |
+
* @param mixed $location The file location object/string.
|
1140 |
+
* @param string $type File type.
|
1141 |
+
* @param string $slug The plugin/theme slug of the file.
|
1142 |
+
* @param boolean $regex Should a regex search be performed.
|
1143 |
*
|
1144 |
* @return mixed
|
1145 |
*/
|
1147 |
if ( empty( $string ) || ! is_file( $filename ) ) {
|
1148 |
return false;
|
1149 |
}
|
1150 |
+
$output = array();
|
1151 |
+
$linenum = 0;
|
1152 |
$match_count = 0;
|
1153 |
|
1154 |
if ( ! is_object( $location ) ) {
|
1155 |
+
$path = $location;
|
1156 |
$location = explode( DIRECTORY_SEPARATOR, $location );
|
1157 |
+
$file = end( $location );
|
1158 |
+
} else {
|
|
|
1159 |
$path = $location->getPathname();
|
1160 |
$file = $location->getFilename();
|
1161 |
}
|
1164 |
* Check if the filename matches our search pattern
|
1165 |
*/
|
1166 |
if ( stristr( $file, $string ) || ( $regex && preg_match( $string, $file ) ) ) {
|
1167 |
+
$relativepath = str_replace( array( ABSPATH, '\\', '/' ), array(
|
1168 |
+
'',
|
1169 |
+
DIRECTORY_SEPARATOR,
|
1170 |
+
DIRECTORY_SEPARATOR
|
1171 |
+
), $path );
|
1172 |
+
$match_count ++;
|
1173 |
|
1174 |
$editurl = $this->create_edit_link( $path, $linenum );
|
1175 |
|
1194 |
}
|
1195 |
|
1196 |
$readfile = @fopen( $filename, "r" );
|
1197 |
+
if ( $readfile ) {
|
1198 |
+
while ( ( $readline = fgets( $readfile ) ) !== false ) {
|
|
|
|
|
1199 |
$string_preview_is_cut = false;
|
1200 |
+
$linenum ++;
|
1201 |
/**
|
1202 |
* If our string is found in this line, output the line number and other data
|
1203 |
*/
|
1204 |
+
if ( ( ! $regex && stristr( $readline, $string ) ) || ( $regex && preg_match( $string, $readline ) ) ) {
|
|
|
1205 |
/**
|
1206 |
* Prepare the visual path for the end user
|
1207 |
* Removes path leading up to WordPress root and ensures consistent directory separators
|
1208 |
*/
|
1209 |
+
$relativepath = str_replace( array( ABSPATH, '\\', '/' ), array(
|
1210 |
+
'',
|
1211 |
+
DIRECTORY_SEPARATOR,
|
1212 |
+
DIRECTORY_SEPARATOR
|
1213 |
+
), $path );
|
1214 |
+
$match_count ++;
|
1215 |
|
1216 |
/**
|
1217 |
* Create the URL to take the user to the editor
|
1218 |
*/
|
1219 |
$editurl = $this->create_edit_link( $path, $linenum );
|
1220 |
|
1221 |
+
$string_preview = $readline;
|
1222 |
+
if ( strlen( $string_preview ) > ( strlen( $string ) + $this->excerpt_length ) ) {
|
1223 |
$string_location = strpos( $string_preview, $string );
|
1224 |
|
1225 |
$string_location_start = $string_location - $this->excerpt_length;
|
1227 |
$string_location_start = 0;
|
1228 |
}
|
1229 |
|
1230 |
+
$string_location_end = ( strlen( $string ) + ( $this->excerpt_length * 2 ) );
|
1231 |
if ( $string_location_end > strlen( $string_preview ) ) {
|
1232 |
$string_location_end = strlen( $string_preview );
|
1233 |
}
|
1234 |
|
1235 |
+
$string_preview = substr( $string_preview, $string_location_start, $string_location_end );
|
1236 |
$string_preview_is_cut = true;
|
1237 |
}
|
1238 |
|
1239 |
if ( $regex ) {
|
1240 |
$string_preview = preg_replace( preg_replace( '/\/(.+)\//', '/($1)/', $string ), '<strong>$1</strong>', esc_html( $string_preview ) );
|
1241 |
+
} else {
|
|
|
1242 |
$string_preview = str_ireplace( $string, '<strong>' . $string . '</strong>', esc_html( $string_preview ) );
|
1243 |
}
|
1244 |
if ( $string_preview_is_cut ) {
|
1267 |
}
|
1268 |
|
1269 |
fclose( $readfile );
|
1270 |
+
} else {
|
|
|
1271 |
/**
|
1272 |
* The file was unreadable, give the user a friendly notification
|
1273 |
*/
|
uninstall.php
CHANGED
@@ -1,6 +1,11 @@
|
|
1 |
<?php
|
2 |
//if uninstall not called from WordPress exit
|
3 |
-
if ( !defined( 'WP_UNINSTALL_PLUGIN' ) )
|
4 |
exit();
|
|
|
5 |
|
6 |
-
|
|
|
|
|
|
|
|
1 |
<?php
|
2 |
//if uninstall not called from WordPress exit
|
3 |
+
if ( !defined( 'WP_UNINSTALL_PLUGIN' ) ) {
|
4 |
exit();
|
5 |
+
}
|
6 |
|
7 |
+
global $wpdb;
|
8 |
+
$options = $wpdb->get_results( "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE 'string-locator-%'" );
|
9 |
+
foreach( $options AS $option ) {
|
10 |
+
delete_option( $option->option_name );
|
11 |
+
}
|