WP Htaccess Editor - Version 1.60

Version Description

Download this release

Release Info

Developer WebFactory
Plugin Icon 128x128 WP Htaccess Editor
Version 1.60
Comparing to
See all releases

Code changes from version 1.55 to 1.60

css/wp-htaccess-editor.css CHANGED
@@ -3,56 +3,56 @@
3
  * (c) WebFactory Ltd, 2018-2019
4
  */
5
 
6
- .tools_page_wp-htaccess-editor .card {
7
  padding: 1em 2em 1em 2em;
8
  width: 520px;
9
  }
10
 
11
- .tools_page_wp-htaccess-editor h1 img {
12
  max-height: 50px;
13
  width: auto;
14
  }
15
 
16
- .tools_page_wp-htaccess-editor .toggle-card {
17
  position: absolute;
18
  right: 2em;
19
  top: 2.2em;
20
  text-decoration: none;
21
  }
22
 
23
- .tools_page_wp-htaccess-editor .card.collapsed p,
24
- .tools_page_wp-htaccess-editor .card.collapsed b,
25
- .tools_page_wp-htaccess-editor .card.collapsed ul {
26
  display: none;
27
  }
28
 
29
- .tools_page_wp-htaccess-editor .textcenter {
30
  text-align: center;
31
  }
32
 
33
- .tools_page_wp-htaccess-editor .button.disabled {
34
  pointer-events: none;
35
  cursor: not-allowed;
36
  }
37
 
38
- .tools_page_wp-htaccess-editor.wp-core-ui .button,
39
- .tools_page_wp-htaccess-editor.wp-core-ui .button-primary,
40
- .tools_page_wp-htaccess-editor.wp-core-ui .button-secondary {
41
  border-radius: 0;
42
  }
43
 
44
- .tools_page_wp-htaccess-editor .button {
45
  box-shadow: none;
46
  text-shadow: none;
47
  }
48
 
49
- .tools_page_wp-htaccess-editor .plain-list {
50
- margin-top: 5px;
51
- list-style-type: circle;
52
- list-style-position: inside;
53
- }
54
 
55
- .tools_page_wp-htaccess-editor .plain-list li {
56
  text-indent: -18px;
57
  padding-left: 23px;
58
  line-height: 23px;
@@ -84,54 +84,55 @@
84
  margin-right: 15px;
85
  }
86
 
87
- .tools_page_wp-htaccess-editor .red {
88
  color: #dd3036;
89
  }
90
 
91
- .tools_page_wp-htaccess-editor .green {
92
  color: #1daf1d;
93
  }
94
 
95
- .tools_page_wp-htaccess-editor .dismiss-notice-rate {
96
  vertical-align: bottom;
97
  margin-left: 10px;
98
  }
99
 
100
- .tools_page_wp-htaccess-editor .swal2-container {
101
  z-index: 99999;
102
  }
103
 
104
- .tools_page_wp-htaccess-editor .swal2-container.swal2-shown {
105
- background-color: rgba(0,0,0,.6);
106
  }
107
 
108
- .tools_page_wp-htaccess-editor .swal2-popup .swal2-title {
109
  line-height: 1;
110
  }
111
 
112
- .tools_page_wp-htaccess-editor code {
113
  white-space: nowrap;
114
  }
115
 
116
- .tools_page_wp-htaccess-editor p {
117
  line-height: 1.7;
118
  }
119
 
120
- .tools_page_wp-htaccess-editor .rotating {
121
- -webkit-animation:spin 1.5s linear infinite;
122
- -moz-animation:spin 1.5s linear infinite;
123
- animation:spin 1.5s linear infinite;
124
  }
125
 
126
- .tools_page_wp-htaccess-editor .notice-error {
127
  border-color: #dd3036;
128
  }
129
 
130
- .tools_page_wp-htaccess-editor .swal2-popup {
131
  border-radius: 0;
132
  }
133
 
134
- #htaccess-editor-wrap .CodeMirror, #htaccess-editor-wrap textarea {
 
135
  width: 574px;
136
  min-width: 300px;
137
  max-width: 100%;
@@ -157,6 +158,7 @@
157
  }
158
  @keyframes spin {
159
  100% {
160
- -webkit-transform: rotate(-360deg); transform:rotate(-360deg);
 
161
  }
162
  }
3
  * (c) WebFactory Ltd, 2018-2019
4
  */
5
 
6
+ .settings_page_wp-htaccess-editor .card {
7
  padding: 1em 2em 1em 2em;
8
  width: 520px;
9
  }
10
 
11
+ .settings_page_wp-htaccess-editor h1 img {
12
  max-height: 50px;
13
  width: auto;
14
  }
15
 
16
+ .settings_page_wp-htaccess-editor .toggle-card {
17
  position: absolute;
18
  right: 2em;
19
  top: 2.2em;
20
  text-decoration: none;
21
  }
22
 
23
+ .settings_page_wp-htaccess-editor .card.collapsed p,
24
+ .settings_page_wp-htaccess-editor .card.collapsed b,
25
+ .settings_page_wp-htaccess-editor .card.collapsed ul {
26
  display: none;
27
  }
28
 
29
+ .settings_page_wp-htaccess-editor .textcenter {
30
  text-align: center;
31
  }
32
 
33
+ .settings_page_wp-htaccess-editor .button.disabled {
34
  pointer-events: none;
35
  cursor: not-allowed;
36
  }
37
 
38
+ .settings_page_wp-htaccess-editor.wp-core-ui .button,
39
+ .settings_page_wp-htaccess-editor.wp-core-ui .button-primary,
40
+ .settings_page_wp-htaccess-editor.wp-core-ui .button-secondary {
41
  border-radius: 0;
42
  }
43
 
44
+ .settings_page_wp-htaccess-editor .button {
45
  box-shadow: none;
46
  text-shadow: none;
47
  }
48
 
49
+ .settings_page_wp-htaccess-editor .plain-list {
50
+ margin-top: 5px;
51
+ list-style-type: circle;
52
+ list-style-position: inside;
53
+ }
54
 
55
+ .settings_page_wp-htaccess-editor .plain-list li {
56
  text-indent: -18px;
57
  padding-left: 23px;
58
  line-height: 23px;
84
  margin-right: 15px;
85
  }
86
 
87
+ .settings_page_wp-htaccess-editor .red {
88
  color: #dd3036;
89
  }
90
 
91
+ .settings_page_wp-htaccess-editor .green {
92
  color: #1daf1d;
93
  }
94
 
95
+ .settings_page_wp-htaccess-editor .dismiss-notice-rate {
96
  vertical-align: bottom;
97
  margin-left: 10px;
98
  }
99
 
100
+ .settings_page_wp-htaccess-editor .swal2-container {
101
  z-index: 99999;
102
  }
103
 
104
+ .settings_page_wp-htaccess-editor .swal2-container.swal2-shown {
105
+ background-color: rgba(0, 0, 0, 0.6);
106
  }
107
 
108
+ .settings_page_wp-htaccess-editor .swal2-popup .swal2-title {
109
  line-height: 1;
110
  }
111
 
112
+ .settings_page_wp-htaccess-editor code {
113
  white-space: nowrap;
114
  }
115
 
116
+ .settings_page_wp-htaccess-editor p {
117
  line-height: 1.7;
118
  }
119
 
120
+ .settings_page_wp-htaccess-editor .rotating {
121
+ -webkit-animation: spin 1.5s linear infinite;
122
+ -moz-animation: spin 1.5s linear infinite;
123
+ animation: spin 1.5s linear infinite;
124
  }
125
 
126
+ .settings_page_wp-htaccess-editor .notice-error {
127
  border-color: #dd3036;
128
  }
129
 
130
+ .settings_page_wp-htaccess-editor .swal2-popup {
131
  border-radius: 0;
132
  }
133
 
134
+ #htaccess-editor-wrap .CodeMirror,
135
+ #htaccess-editor-wrap textarea {
136
  width: 574px;
137
  min-width: 300px;
138
  max-width: 100%;
158
  }
159
  @keyframes spin {
160
  100% {
161
+ -webkit-transform: rotate(-360deg);
162
+ transform: rotate(-360deg);
163
  }
164
  }
js/wp-htaccess-editor.js CHANGED
@@ -3,7 +3,6 @@
3
  * (c) WebFactory Ltd, 2018-2019
4
  */
5
 
6
-
7
  jQuery(document).ready(function($) {
8
  var wphe_changed = false;
9
 
@@ -17,6 +16,12 @@ jQuery(document).ready(function($) {
17
  wphe_changed = true;
18
  });
19
 
 
 
 
 
 
 
20
  // kill WP's beforeunload
21
  $(window).off('beforeunload');
22
 
@@ -26,21 +31,36 @@ jQuery(document).ready(function($) {
26
  return true;
27
  }
28
  });
29
- }); // CodeMirror setup
30
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
  // init code editor
33
- wp.themePluginEditor.init($('#htaccess-editor-wrap'), wp_htaccess_editor.cm_settings);
 
 
 
34
  wp.themePluginEditor.themeOrPlugin = 'theme';
35
 
36
-
37
  // display a message while an action is performed
38
  function block_ui(message) {
39
  tmp = swal({
40
  text: message,
41
  type: false,
42
  imageUrl: wp_htaccess_editor.loading_icon_url,
43
- onOpen: () => { $(swal.getImage()).addClass('rotating'); },
 
 
44
  imageWidth: 100,
45
  imageHeight: 100,
46
  imageAlt: message,
@@ -54,7 +74,6 @@ jQuery(document).ready(function($) {
54
  return tmp;
55
  } // block_ui
56
 
57
-
58
  // display dialog to confirm action
59
  function confirm_action(title, question, btn_confirm, btn_cancel) {
60
  tmp = swal({
@@ -72,7 +91,6 @@ jQuery(document).ready(function($) {
72
  return tmp;
73
  } // confirm_action
74
 
75
-
76
  // dismiss notice / pointer
77
  $('.wphe-dismiss-notice').on('click', function(e) {
78
  notice_name = $(this).data('notice');
@@ -80,12 +98,15 @@ jQuery(document).ready(function($) {
80
  return true;
81
  }
82
 
83
- $.get(ajaxurl, { notice_name: notice_name,
84
- _ajax_nonce: wp_htaccess_editor.nonce_dismiss_notice,
85
- action: 'wp_htaccess_editor_dismiss_notice'
 
86
  });
87
 
88
- $(this).parents('.notice-wrapper').fadeOut();
 
 
89
 
90
  if (notice_name == 'editor-warning') {
91
  $('#wphe-buttons').fadeIn();
@@ -95,13 +116,16 @@ jQuery(document).ready(function($) {
95
  return false;
96
  }); // dismiss notice
97
 
98
-
99
  // collapse / expand card
100
  $('.card').on('click', '.toggle-card', function(e) {
101
  e.preventDefault();
102
 
103
- card = $(this).parents('.card').toggleClass('collapsed');
104
- $('.dashicons', this).toggleClass('dashicons-arrow-up-alt2').toggleClass('dashicons-arrow-down-alt2');
 
 
 
 
105
  $(this).blur();
106
 
107
  cards = localStorage.getItem('wp-htaccess-editor-cards');
@@ -121,7 +145,6 @@ jQuery(document).ready(function($) {
121
  return false;
122
  }); // toggle-card
123
 
124
-
125
  // init cards; collapse those that need collapsing
126
  cards = localStorage.getItem('wp-htaccess-editor-cards');
127
  if (cards != null) {
@@ -133,7 +156,6 @@ jQuery(document).ready(function($) {
133
  }
134
  });
135
 
136
-
137
  // save htaccess file
138
  $('#wphe_save_htaccess').click(function(e) {
139
  e.preventDefault();
@@ -147,36 +169,48 @@ jQuery(document).ready(function($) {
147
  subaction: 'save_htaccess',
148
  new_content: wp.themePluginEditor.instance.codemirror.getValue()
149
  }
150
- }).always(function(data) {
151
- swal.close();
152
- }).done(function(data) {
153
- if (typeof data.success != 'undefined' && data.success) {
154
- jQuery.get(wp_htaccess_editor.home_url).always(function(data, text, xhr) {
155
- status = xhr.status;
156
- wphe_changed = false;
157
- if (status.substr(0, 1) != '2') {
158
- swal({ type: 'error', title: wp_htaccess_editor.site_error });
159
- } else {
160
- swal({ type: 'success', title: wp_htaccess_editor.save_success, showConfirmButton: false, timer: 1000 });
161
- }
162
- })
163
- } else if (typeof data.success != 'undefined' && !data.success) {
164
- swal({ type: 'error', title: data.data });
165
- } else {
166
- swal({ type: 'error', title: wp_htaccess_editor.undocumented_error });
167
- }
168
- }).fail(function(data) {
169
- if (data.data) {
170
- swal({ type: 'error', title: wp_htaccess_editor.documented_error + ' ' + data.data });
171
- } else {
172
- swal({ type: 'error', title: wp_htaccess_editor.undocumented_error });
173
- }
174
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
175
 
176
  return false;
177
  }); // save htaccess
178
 
179
-
180
  // restore htaccess backup from DB
181
  $('#wphe_restore_htaccess').click(function(e) {
182
  message = wp_htaccess_editor.restore_message;
@@ -190,7 +224,7 @@ jQuery(document).ready(function($) {
190
  cancelButtonText: wp_htaccess_editor.cancel_button,
191
  confirmButtonColor: '#dd3036',
192
  width: 600
193
- }).then((result) => {
194
  if (result.value === true) {
195
  block_ui(wp_htaccess_editor.restoring);
196
  $.post({
@@ -200,18 +234,33 @@ jQuery(document).ready(function($) {
200
  _ajax_nonce: wp_htaccess_editor.nonce_do_action,
201
  subaction: 'restore_htaccess_from_db'
202
  }
203
- }).always(function(data) {
204
- swal.close();
205
- }).done(function(data) {
206
- if (data.success) {
207
- wphe_changed = false;
208
- swal({ type: 'success', title: wp_htaccess_editor.restore_success, onClose: function() { location.reload(); } });
209
- } else {
210
- swal({ type: 'error', title: wp_htaccess_editor.documented_error + ' ' + data.data });
211
- }
212
- }).fail(function(data) {
213
- swal({ type: 'error', title: wp_htaccess_editor.undocumented_error });
214
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  return false;
216
  }
217
  });
3
  * (c) WebFactory Ltd, 2018-2019
4
  */
5
 
 
6
  jQuery(document).ready(function($) {
7
  var wphe_changed = false;
8
 
16
  wphe_changed = true;
17
  });
18
 
19
+ // detect and save editor size change
20
+ wphe_cm.on('update', function(e) {
21
+ localStorage.setItem('wphe-editor-width', e.display.lastWrapWidth);
22
+ localStorage.setItem('wphe-editor-height', e.display.lastWrapHeight);
23
+ });
24
+
25
  // kill WP's beforeunload
26
  $(window).off('beforeunload');
27
 
31
  return true;
32
  }
33
  });
 
34
 
35
+ let wphe_width = parseInt(localStorage.getItem('wphe-editor-width'), 10);
36
+ let wphe_height = parseInt(localStorage.getItem('wphe-editor-height'), 10);
37
+
38
+ if (wphe_width > 0 && wphe_height > 0) {
39
+ $('.CodeMirror')
40
+ .width(wphe_width)
41
+ .height(wphe_height);
42
+ $('#enable-editor-notice')
43
+ .width(wphe_width)
44
+ .height(wphe_height);
45
+ }
46
+ }); // CodeMirror setup
47
 
48
  // init code editor
49
+ wp.themePluginEditor.init(
50
+ $('#htaccess-editor-wrap'),
51
+ wp_htaccess_editor.cm_settings
52
+ );
53
  wp.themePluginEditor.themeOrPlugin = 'theme';
54
 
 
55
  // display a message while an action is performed
56
  function block_ui(message) {
57
  tmp = swal({
58
  text: message,
59
  type: false,
60
  imageUrl: wp_htaccess_editor.loading_icon_url,
61
+ onOpen: () => {
62
+ $(swal.getImage()).addClass('rotating');
63
+ },
64
  imageWidth: 100,
65
  imageHeight: 100,
66
  imageAlt: message,
74
  return tmp;
75
  } // block_ui
76
 
 
77
  // display dialog to confirm action
78
  function confirm_action(title, question, btn_confirm, btn_cancel) {
79
  tmp = swal({
91
  return tmp;
92
  } // confirm_action
93
 
 
94
  // dismiss notice / pointer
95
  $('.wphe-dismiss-notice').on('click', function(e) {
96
  notice_name = $(this).data('notice');
98
  return true;
99
  }
100
 
101
+ $.get(ajaxurl, {
102
+ notice_name: notice_name,
103
+ _ajax_nonce: wp_htaccess_editor.nonce_dismiss_notice,
104
+ action: 'wp_htaccess_editor_dismiss_notice'
105
  });
106
 
107
+ $(this)
108
+ .parents('.notice-wrapper')
109
+ .fadeOut();
110
 
111
  if (notice_name == 'editor-warning') {
112
  $('#wphe-buttons').fadeIn();
116
  return false;
117
  }); // dismiss notice
118
 
 
119
  // collapse / expand card
120
  $('.card').on('click', '.toggle-card', function(e) {
121
  e.preventDefault();
122
 
123
+ card = $(this)
124
+ .parents('.card')
125
+ .toggleClass('collapsed');
126
+ $('.dashicons', this)
127
+ .toggleClass('dashicons-arrow-up-alt2')
128
+ .toggleClass('dashicons-arrow-down-alt2');
129
  $(this).blur();
130
 
131
  cards = localStorage.getItem('wp-htaccess-editor-cards');
145
  return false;
146
  }); // toggle-card
147
 
 
148
  // init cards; collapse those that need collapsing
149
  cards = localStorage.getItem('wp-htaccess-editor-cards');
150
  if (cards != null) {
156
  }
157
  });
158
 
 
159
  // save htaccess file
160
  $('#wphe_save_htaccess').click(function(e) {
161
  e.preventDefault();
169
  subaction: 'save_htaccess',
170
  new_content: wp.themePluginEditor.instance.codemirror.getValue()
171
  }
172
+ })
173
+ .always(function(data) {
174
+ swal.close();
175
+ })
176
+ .done(function(data) {
177
+ if (typeof data.success != 'undefined' && data.success) {
178
+ jQuery
179
+ .get(wp_htaccess_editor.home_url)
180
+ .always(function(data, text, xhr) {
181
+ status = xhr.status;
182
+ wphe_changed = false;
183
+ if (status.substr(0, 1) != '2') {
184
+ swal({ type: 'error', title: wp_htaccess_editor.site_error });
185
+ } else {
186
+ swal({
187
+ type: 'success',
188
+ title: wp_htaccess_editor.save_success,
189
+ showConfirmButton: false,
190
+ timer: 1000
191
+ });
192
+ }
193
+ });
194
+ } else if (typeof data.success != 'undefined' && !data.success) {
195
+ swal({ type: 'error', title: data.data });
196
+ } else {
197
+ swal({ type: 'error', title: wp_htaccess_editor.undocumented_error });
198
+ }
199
+ })
200
+ .fail(function(data) {
201
+ if (data.data) {
202
+ swal({
203
+ type: 'error',
204
+ title: wp_htaccess_editor.documented_error + ' ' + data.data
205
+ });
206
+ } else {
207
+ swal({ type: 'error', title: wp_htaccess_editor.undocumented_error });
208
+ }
209
+ });
210
 
211
  return false;
212
  }); // save htaccess
213
 
 
214
  // restore htaccess backup from DB
215
  $('#wphe_restore_htaccess').click(function(e) {
216
  message = wp_htaccess_editor.restore_message;
224
  cancelButtonText: wp_htaccess_editor.cancel_button,
225
  confirmButtonColor: '#dd3036',
226
  width: 600
227
+ }).then(result => {
228
  if (result.value === true) {
229
  block_ui(wp_htaccess_editor.restoring);
230
  $.post({
234
  _ajax_nonce: wp_htaccess_editor.nonce_do_action,
235
  subaction: 'restore_htaccess_from_db'
236
  }
237
+ })
238
+ .always(function(data) {
239
+ swal.close();
240
+ })
241
+ .done(function(data) {
242
+ if (data.success) {
243
+ wphe_changed = false;
244
+ swal({
245
+ type: 'success',
246
+ title: wp_htaccess_editor.restore_success,
247
+ onClose: function() {
248
+ location.reload();
249
+ }
250
+ });
251
+ } else {
252
+ swal({
253
+ type: 'error',
254
+ title: wp_htaccess_editor.documented_error + ' ' + data.data
255
+ });
256
+ }
257
+ })
258
+ .fail(function(data) {
259
+ swal({
260
+ type: 'error',
261
+ title: wp_htaccess_editor.undocumented_error
262
+ });
263
+ });
264
  return false;
265
  }
266
  });
readme.txt CHANGED
@@ -1,25 +1,29 @@
1
  === Htaccess Editor - Safely Edit Htaccess File ===
2
- Tags: htaccess, htaccess editor, htaccess file, htaccess backup, fix htaccess, modify htaccess, file editor
3
  Contributors: WebFactory, UnderConstructionPage, googlemapswidget, securityninja, wpreset
4
  Requires at least: 4.0
5
  Requires PHP: 5.2
6
- Tested up to: 5.0
7
- Stable tag: 1.55
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
11
- A safe & simple htaccess file editor with automatic backup.
12
 
13
  == Description ==
14
 
15
  <a href="https://wphtaccess.com/?utm_source=wordpressorg&utm_medium=content&utm_campaign=wp-htaccess-editor&utm_term=readme-top">WP Htaccess Editor</a> provides a **simple, safe & fast way** to edit the site's .htaccess file from WP admin. It automatically creates a backup every time you make a change to the htaccess file. Backups can be restored directly from the plugin, or via FTP if the errors in .htaccess file prevent WP from running normally. For all questions, including support please use the official <a href="https://wordpress.org/support/plugin/wp-htaccess-editor">forum</a>.
16
 
17
- Access WP Htaccess Editor via the "Tools" menu in WP admin.
18
 
19
  #### Automatic Backups
20
 
21
  Htaccess Editor makes automatic backups of htaccess file every time you make a change to it. Backups are located in `/wp-content/htaccess-editor-backups/` and timestamped so you can easily find the latest htaccess backup and restore it.
22
 
 
 
 
 
23
  The plugin was originally developed by <a href="https://profiles.wordpress.org/lukenzi">Lukenzi</a> in March of 2011.
24
 
25
  == Installation ==
@@ -29,14 +33,14 @@ Follow the usual routine;
29
  1. Open WordPress admin, go to Plugins, click Add New
30
  2. Enter "htaccess editor" in search and hit Enter
31
  3. Plugin will show up as the first on the list, click "Install Now"
32
- 4. Activate & open plugin's settings page located under the Tools menu
33
 
34
  Or if needed, upload manually;
35
 
36
  1. Download the latest stable version from from <a href="https://downloads.wordpress.org/plugin/wp-htaccess-editor.latest-stable.zip">downloads.wordpress.org/plugin/wp-htaccess-editor.latest-stable.zip</a>
37
  2. Unzip it and upload to _/wp-content/plugins/_
38
  3. Open WordPress admin - Plugins and click "Activate" next to "WP Htaccess Editor"
39
- 4. Open plugin's admin page located under the Tools menu
40
 
41
 
42
  == Screenshots ==
@@ -47,6 +51,13 @@ Or if needed, upload manually;
47
 
48
  == Changelog ==
49
 
 
 
 
 
 
 
 
50
  = v1.55 =
51
  * 2019/01/15
52
  * added code editor resize feature
1
  === Htaccess Editor - Safely Edit Htaccess File ===
2
+ Tags: htaccess, htaccess editor, htaccess file, htaccess backup, fix htaccess, modify htaccess, file editor, htaccess backup
3
  Contributors: WebFactory, UnderConstructionPage, googlemapswidget, securityninja, wpreset
4
  Requires at least: 4.0
5
  Requires PHP: 5.2
6
+ Tested up to: 5.2
7
+ Stable tag: 1.60
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
11
+ A safe & simple htaccess file editor. Automatically creates htaccess file backups.
12
 
13
  == Description ==
14
 
15
  <a href="https://wphtaccess.com/?utm_source=wordpressorg&utm_medium=content&utm_campaign=wp-htaccess-editor&utm_term=readme-top">WP Htaccess Editor</a> provides a **simple, safe & fast way** to edit the site's .htaccess file from WP admin. It automatically creates a backup every time you make a change to the htaccess file. Backups can be restored directly from the plugin, or via FTP if the errors in .htaccess file prevent WP from running normally. For all questions, including support please use the official <a href="https://wordpress.org/support/plugin/wp-htaccess-editor">forum</a>.
16
 
17
+ Access WP Htaccess Editor via WP Admin - Settings menu.
18
 
19
  #### Automatic Backups
20
 
21
  Htaccess Editor makes automatic backups of htaccess file every time you make a change to it. Backups are located in `/wp-content/htaccess-editor-backups/` and timestamped so you can easily find the latest htaccess backup and restore it.
22
 
23
+ #### WordPress Network (WPMU) Support
24
+ WP Htaccess Editor is fully compatible and tested with WP Network (WPMU). It shows up under the Settings menu in network admin. It's not available in individual sites as there is only one .htaccess file per network.
25
+
26
+
27
  The plugin was originally developed by <a href="https://profiles.wordpress.org/lukenzi">Lukenzi</a> in March of 2011.
28
 
29
  == Installation ==
33
  1. Open WordPress admin, go to Plugins, click Add New
34
  2. Enter "htaccess editor" in search and hit Enter
35
  3. Plugin will show up as the first on the list, click "Install Now"
36
+ 4. Activate & open plugin's settings page located under the Settings menu
37
 
38
  Or if needed, upload manually;
39
 
40
  1. Download the latest stable version from from <a href="https://downloads.wordpress.org/plugin/wp-htaccess-editor.latest-stable.zip">downloads.wordpress.org/plugin/wp-htaccess-editor.latest-stable.zip</a>
41
  2. Unzip it and upload to _/wp-content/plugins/_
42
  3. Open WordPress admin - Plugins and click "Activate" next to "WP Htaccess Editor"
43
+ 4. Open plugin's admin page located under the Settings menu
44
 
45
 
46
  == Screenshots ==
51
 
52
  == Changelog ==
53
 
54
+ = v1.60 =
55
+ * 2019/03/12
56
+ * fixed a few bugs
57
+ * new: editor size is persistent; saved in localStorage
58
+ * menu item moved from Tools to Settings
59
+ * full WordPress Network (WPMU) compatibility
60
+
61
  = v1.55 =
62
  * 2019/01/15
63
  * added code editor resize feature
wp-htaccess-editor.php CHANGED
@@ -1,12 +1,13 @@
1
  <?php
2
- /*
3
  Plugin Name: WP Htaccess Editor
4
  Plugin URI: https://wphtaccess.com/
5
  Description: Safe and easy way to edit the .htaccess file directly from WP admin without using FTP.
6
- Version: 1.55
7
  Author: WebFactory Ltd
8
  Author URI: https://www.webfactoryltd.com/
9
  Text Domain: wp-htaccess-editor
 
10
 
11
  Copyright 2011 - 2018 Lukenzi (email: lukenzi@gmail.com)
12
  Copyright 2018 - 2019 WebFactory Ltd (email: support@webfactoryltd.com)
@@ -32,7 +33,8 @@ if (!defined('ABSPATH')) {
32
  }
33
 
34
 
35
- class WP_Htaccess_Editor {
 
36
  protected static $instance = null;
37
  public $version = 0;
38
  public $plugin_url = '';
@@ -47,7 +49,8 @@ class WP_Htaccess_Editor {
47
  *
48
  * @return WP_Htaccess_Editor
49
  */
50
- static function get_instance() {
 
51
  if (false == is_a(self::$instance, 'WP_Htaccess_Editor')) {
52
  self::$instance = new WP_Htaccess_Editor();
53
  }
@@ -61,7 +64,8 @@ class WP_Htaccess_Editor {
61
  *
62
  * @return null
63
  */
64
- private function __construct() {
 
65
  $this->version = $this->get_plugin_version();
66
  $this->plugin_url = plugin_dir_url(__FILE__);
67
  $this->plugin_basename = plugin_basename(__FILE__);
@@ -85,7 +89,8 @@ class WP_Htaccess_Editor {
85
  *
86
  * @return string
87
  */
88
- function get_plugin_version() {
 
89
  $plugin_data = get_file_data(__FILE__, array('version' => 'Version'), 'plugin');
90
 
91
  return $plugin_data['version'];
@@ -99,13 +104,14 @@ class WP_Htaccess_Editor {
99
  *
100
  * @return array
101
  */
102
- function plugin_action_links($links) {
 
103
  // whole plugin is for admins only
104
  if (false === current_user_can('administrator')) {
105
  return $links;
106
  }
107
 
108
- $settings_link = '<a href="' . admin_url('tools.php?page=wp-htaccess-editor') . '" title="' . __('Edit .htaccess file', 'wp-htaccess-editor') . '">' . __('Edit .htaccess file', 'wp-htaccess-editor') . '</a>';
109
 
110
  array_unshift($links, $settings_link);
111
 
@@ -121,7 +127,8 @@ class WP_Htaccess_Editor {
121
  *
122
  * @return array
123
  */
124
- function plugin_meta_links($links, $file) {
 
125
  if ($file !== $this->plugin_basename) {
126
  return $links;
127
  }
@@ -143,10 +150,11 @@ class WP_Htaccess_Editor {
143
  *
144
  * @return bool
145
  */
146
- function is_plugin_page() {
 
147
  $current_screen = get_current_screen();
148
 
149
- if ($current_screen->id === 'tools_page_wp-htaccess-editor') {
150
  return true;
151
  } else {
152
  return false;
@@ -161,12 +169,13 @@ class WP_Htaccess_Editor {
161
  *
162
  * @return string
163
  */
164
- function admin_footer_text($text_org) {
 
165
  if (false === $this->is_plugin_page()) {
166
  return $text_org;
167
  }
168
 
169
- $text = '<i><a target="_blank" href="' . $this->generate_web_link('admin_footer') . '">WP Htaccess Editor</a> v' . $this->version . ' by <a href="https://www.webfactoryltd.com/" title="' . __('Visit our site to get more great plugins', 'wp-htaccess-editor'). '" target="_blank">WebFactory Ltd</a>.';
170
  $text .= ' Please <a target="_blank" href="https://wordpress.org/support/plugin/wp-htaccess-editor/reviews/#new-post" title="' . __('Rate the plugin', 'wp-htaccess-editor') . '">' . __('Rate the plugin ★★★★★', 'wp-htaccess-editor') . '</a>.</i> ';
171
 
172
  return $text;
@@ -178,7 +187,8 @@ class WP_Htaccess_Editor {
178
  *
179
  * @return null
180
  */
181
- function load_textdomain() {
 
182
  load_plugin_textdomain('wp-htaccess-editor');
183
  } // load_textdomain
184
 
@@ -188,7 +198,8 @@ class WP_Htaccess_Editor {
188
  *
189
  * @return object
190
  */
191
- private function setup_wp_filesystem() {
 
192
  global $wp_filesystem;
193
 
194
  if (empty($wp_filesystem)) {
@@ -206,7 +217,8 @@ class WP_Htaccess_Editor {
206
  *
207
  * @return string
208
  */
209
- function get_backup_folder() {
 
210
  $folder = trailingslashit(WP_CONTENT_DIR) . trailingslashit($this->backup_folder);
211
 
212
  return $folder;
@@ -220,7 +232,8 @@ class WP_Htaccess_Editor {
220
  *
221
  * @return string
222
  */
223
- function get_htaccess_path($folder_only = false) {
 
224
  if ($folder_only) {
225
  return get_home_path();
226
  } else {
@@ -234,7 +247,8 @@ class WP_Htaccess_Editor {
234
  *
235
  * @return string
236
  */
237
- function get_htaccess_content() {
 
238
  $content = $this->wp_filesystem->get_contents($this->get_htaccess_path());
239
 
240
  return $content;
@@ -246,7 +260,8 @@ class WP_Htaccess_Editor {
246
  *
247
  * @return bool
248
  */
249
- function is_htaccess_writable() {
 
250
  $htaccess_path = $this->get_htaccess_path();
251
 
252
  return $this->wp_filesystem->is_writable($htaccess_path);
@@ -258,7 +273,8 @@ class WP_Htaccess_Editor {
258
  *
259
  * @return bool
260
  */
261
- function is_htaccess_readable() {
 
262
  $htaccess_path = $this->get_htaccess_path();
263
 
264
  return $this->wp_filesystem->is_readable($htaccess_path);
@@ -270,7 +286,8 @@ class WP_Htaccess_Editor {
270
  *
271
  * @return array
272
  */
273
- private function load_options() {
 
274
  $options = get_option('wp-htaccess-editor', array());
275
  $change = false;
276
 
@@ -300,7 +317,8 @@ class WP_Htaccess_Editor {
300
  *
301
  * @return array
302
  */
303
- function get_meta() {
 
304
  return $this->options['meta'];
305
  } // get_meta
306
 
@@ -312,7 +330,8 @@ class WP_Htaccess_Editor {
312
  *
313
  * @return bool|array
314
  */
315
- function get_dismissed_notices($notice_name = '') {
 
316
  $notices = $this->options['dismissed_notices'];
317
 
318
  if (empty($notice_name)) {
@@ -334,7 +353,8 @@ class WP_Htaccess_Editor {
334
  *
335
  * @return array
336
  */
337
- function get_options($option_key = '') {
 
338
  if (empty($option_key)) {
339
  return $this->options['options'];
340
  } else {
@@ -355,7 +375,8 @@ class WP_Htaccess_Editor {
355
  *
356
  * @return bool
357
  */
358
- private function update_options($key, $data) {
 
359
  if (false === in_array($key, array('options', 'meta', 'dismissed_notices'))) {
360
  trigger_error('Unknown option key used in update_options($key, $data) function.', E_USER_ERROR);
361
  return false;
@@ -369,12 +390,13 @@ class WP_Htaccess_Editor {
369
 
370
 
371
  /**
372
- * Add plugin menu entry under Tools menu
373
  *
374
  * @return null
375
  */
376
- function admin_menu() {
377
- add_management_page(__('WP Htaccess Editor', 'wp-htaccess-editor'), __('WP Htaccess Editor', 'wp-htaccess-editor'), 'administrator', 'wp-htaccess-editor', array($this, 'plugin_page'));
 
378
  } // admin_menu
379
 
380
 
@@ -388,7 +410,8 @@ class WP_Htaccess_Editor {
388
  *
389
  * @return string
390
  */
391
- function generate_web_link($placement = '', $page = '/', $params = array(), $anchor = '') {
 
392
  $base_url = 'https://wphtaccess.com';
393
 
394
  if ('/' != $page) {
@@ -415,7 +438,8 @@ class WP_Htaccess_Editor {
415
  *
416
  * @return null
417
  */
418
- function ajax_dismiss_notice() {
 
419
  check_ajax_referer('wp-htaccess-editor_dismiss_notice');
420
 
421
  // complete plugin is for admins only
@@ -444,7 +468,8 @@ class WP_Htaccess_Editor {
444
  *
445
  * @return bool
446
  */
447
- function dismiss_notice($notice_name) {
 
448
  if ($this->get_dismissed_notices($notice_name)) {
449
  return false;
450
  } else {
@@ -461,11 +486,18 @@ class WP_Htaccess_Editor {
461
  *
462
  * @return array
463
  */
464
- function get_pointers() {
 
465
  $pointers = array();
 
466
 
467
  // TODO: reformat & prepare for translation
468
- $pointers['welcome'] = array('target' => '#menu-tools', 'edge' => 'left', 'align' => 'right', 'content' => 'Thank you for using the <b style="font-weight: 700;">WP Htaccess Editor</b> plugin.<br>Open <a href="' . admin_url('tools.php?page=wp-htaccess-editor'). '">Tools - WP Htaccess Editor</a> to access the editor and start editing the <i>.htaccess</i> file.');
 
 
 
 
 
469
 
470
  return $pointers;
471
  } // get_pointers
@@ -478,7 +510,8 @@ class WP_Htaccess_Editor {
478
  *
479
  * @return null
480
  */
481
- function admin_enqueue_scripts($hook) {
 
482
  // welcome pointer is shown on all pages except WPHE, only to admins, until dismissed
483
  $pointers = $this->get_pointers();
484
  $dismissed_notices = $this->get_dismissed_notices();
@@ -489,7 +522,7 @@ class WP_Htaccess_Editor {
489
  }
490
  } // foreach
491
 
492
- if (current_user_can('administrator') && !empty($pointers) && 'tools_page_wp-htaccess-editor' != $hook) {
493
  $pointers['_nonce_dismiss_pointer'] = wp_create_nonce('wp-htaccess-editor_dismiss_notice');
494
 
495
  wp_enqueue_style('wp-pointer');
@@ -500,33 +533,34 @@ class WP_Htaccess_Editor {
500
  }
501
 
502
  // exit early if not on WPHE page
503
- if ('tools_page_wp-htaccess-editor' != $hook) {
504
  return;
505
  }
506
 
507
- $options = $this->get_options();
508
  $editor_settings['codeEditor'] = wp_enqueue_code_editor(array($this->get_htaccess_path()));
509
  $editor_settings['codeEditor']['codemirror']['mode'] = 'nginx';
510
 
511
- $js_localize = array('undocumented_error' => __('An undocumented error has occurred. Please refresh the page and try again.', 'wp-htaccess-editor'),
512
- 'documented_error' => __('An error has occurred.', 'wp-htaccess-editor'),
513
- 'plugin_name' => __('WP Htaccess Editor', 'wp-htaccess-editor'),
514
- 'home_url' => get_home_url(),
515
- 'settings_url' => admin_url('tools.php?page=wp-htaccess-editor'),
516
- 'loading_icon_url' => $this->plugin_url . 'img/loading-icon.png',
517
- 'cancel_button' => __('Cancel', 'wp-htaccess-editor'),
518
- 'ok_button' => __('OK', 'wp-htaccess-editor'),
519
- 'saving' => __('Saving in progress. Please wait.', 'wp-htaccess-editor'),
520
- 'restoring' => __('Restoring in progress. Please wait.', 'wp-htaccess-editor'),
521
- 'save_success' => __('Changes have been saved.', 'wp-htaccess-editor'),
522
- 'restore_message' => __('This will restore the last saved backup of .htaccess. There is NO UNDO.', 'wp-htaccess-editor'),
523
- 'restore_title' => __('Restore last backup?', 'wp-htaccess-editor'),
524
- 'restore_button' => __('Restore Last Saved Backup of .htaccess', 'wp-htaccess-editor'),
525
- 'restore_success' => __('Backup has been successfully restored. Click OK to reload the page.', 'wp-htaccess-editor'),
526
- 'site_error' => __('There is an error in the .htaccess file and your site is probably no longer accessible.<br><br>DO NOT panic or reload this page. Close this message. First, try the "Restore Last Backup" button. If it doesn\'t work read instruction on this very page on how to restore the site.', 'wp-htaccess-editor'),
527
- 'nonce_dismiss_notice' => wp_create_nonce('wp-htaccess-editor_dismiss_notice'),
528
- 'nonce_do_action' => wp_create_nonce('wp-htaccess-editor_do_action'),
529
- 'cm_settings' => $editor_settings);
 
 
530
 
531
  wp_enqueue_style('wp-codemirror');
532
  wp_enqueue_style('wp-htaccess-editor', $this->plugin_url . 'css/wp-htaccess-editor.css', array(), $this->version);
@@ -541,8 +575,8 @@ class WP_Htaccess_Editor {
541
 
542
  // fix for aggressive plugins that include their CSS files on all pages
543
  wp_dequeue_style('uiStyleSheet');
544
- wp_dequeue_style('wpcufpnAdmin' );
545
- wp_dequeue_style('unifStyleSheet' );
546
  wp_dequeue_style('wpcufpn_codemirror');
547
  wp_dequeue_style('wpcufpn_codemirrorTheme');
548
  wp_dequeue_style('collapse-admin-css');
@@ -560,7 +594,8 @@ class WP_Htaccess_Editor {
560
  *
561
  * @return null
562
  */
563
- function ajax_do_action() {
 
564
  check_ajax_referer('wp-htaccess-editor_do_action');
565
 
566
  if (false === current_user_can('administrator')) {
@@ -607,7 +642,8 @@ class WP_Htaccess_Editor {
607
  *
608
  * @return bool
609
  */
610
- function write_htaccess($new_content) {
 
611
  $htaccess_path = $this->get_htaccess_path();
612
  $result = $this->wp_filesystem->put_contents($htaccess_path, $new_content);
613
  @clearstatcache();
@@ -617,7 +653,7 @@ class WP_Htaccess_Editor {
617
  $meta['edits_count']++;
618
  $this->update_options('meta', $meta);
619
  return true;
620
- } else{
621
  return false;
622
  }
623
  } // write_htaccess
@@ -631,7 +667,8 @@ class WP_Htaccess_Editor {
631
  *
632
  * @return bool
633
  */
634
- function create_htaccess_backup($db_save = true, $file_save = true) {
 
635
  $success = false;
636
  $orig_path = $this->get_htaccess_path();
637
 
@@ -660,7 +697,7 @@ class WP_Htaccess_Editor {
660
 
661
  if ($success) {
662
  return true;
663
- } else{
664
  return false;
665
  }
666
  } // create_htaccess_backup
@@ -671,7 +708,8 @@ class WP_Htaccess_Editor {
671
  *
672
  * @return bool
673
  */
674
- function create_secure_backup_folder() {
 
675
  @clearstatcache();
676
  $secure_path = $this->get_backup_folder() . '.htaccess';
677
  $secure_text = trim('
@@ -692,7 +730,7 @@ class WP_Htaccess_Editor {
692
  return true;
693
  } else {
694
  $write = $this->wp_filesystem->put_contents($secure_path, $secure_text);
695
- if ($write){
696
  return true;
697
  } else {
698
  return false;
@@ -706,7 +744,8 @@ class WP_Htaccess_Editor {
706
  *
707
  * @return bool
708
  */
709
- function restore_db_backup() {
 
710
  $htaccess_path = $this->get_htaccess_path();
711
 
712
  $backup_contents = $this->get_options('last_backup');
@@ -735,11 +774,10 @@ class WP_Htaccess_Editor {
735
  *
736
  * @return null
737
  */
738
- function plugin_page() {
 
739
  $notice_shown = false;
740
  $meta = $this->get_meta();
741
- $notices = $this->get_dismissed_notices();
742
-
743
  $htaccess_content = $this->get_htaccess_content();
744
 
745
  // double check for admin priv
@@ -750,7 +788,7 @@ class WP_Htaccess_Editor {
750
  settings_errors();
751
  echo '<div class="wrap">';
752
  echo '<h1><img src="' . $this->plugin_url . 'img/wp-htaccess-editor-logo.png" alt="' . __('WP Htaccess Editor', 'wp-htaccess-editor') . '" title="' . __('WP Htaccess Editor', 'wp-htaccess-editor') . '"></h1>';
753
- echo '<form id="wp-htaccess-editor-form" action="' . admin_url('tools.php?page=wp-htaccess-editor') . '" method="post" autocomplete="off">';
754
 
755
  // TODO: properly mark for translation
756
  if (false === $this->is_htaccess_readable()) {
@@ -770,16 +808,8 @@ class WP_Htaccess_Editor {
770
  $notice_shown = true;
771
  }
772
 
773
- if (false === $notice_shown && is_multisite()) {
774
- echo '<div class="card notice-wrapper notice-error">';
775
- echo '<h2>' . __('WP Htaccess Editor may not be compatible with multisite!', 'wp-htaccess-editor') . '</h2>';
776
- echo '<p>' . __('Please be careful when using WP Htaccess Editor with multisite enabled. We\'re working on testing it and making fully compatible with WP-MU. <b>Till then please be careful.</b> Thank you for understanding.', 'wp-htaccess-editor') . '</p>';
777
- echo '</div>';
778
- $notice_shown = true;
779
- }
780
-
781
- // ask for rating after a few saves
782
- if ($meta['edits_count'] > 1 && false === $notice_shown && false == $this->get_dismissed_notices('rate')) {
783
  echo '<div class="card notice-wrapper">';
784
  echo '<h2>' . __('Please help us keep the plugin free &amp; up-to-date', 'wp-htaccess-editor') . '</h2>';
785
  echo '<p>' . __('If you use &amp; enjoy WP Htaccess Editor, <b>please rate it on WordPress.org</b>. It only takes a second and helps us keep the plugin free and maintained. Thank you!', 'wp-htaccess-editor') . '</p>';
@@ -797,7 +827,7 @@ class WP_Htaccess_Editor {
797
  echo 'For more details about .htaccess syntax and examples, please visit the <a href="http://httpd.apache.org/docs/current/howto/htaccess.html" target="_blank">official Apache Tutorial</a>.</p>';
798
 
799
  echo '<b>How to restore the site in case of error 500 or white screen caused by .htaccess</b>';
800
- echo '<p>Do not panic. No data is lost, and your site will be up again in minutes. FTP to your site or open the server\'s control panel such as cPanel to locate the .htaccess file in <code>' . $this->get_htaccess_path() . '</code>. Once you find the file there are several options to restore the site.<br><br>The first option is to edit the file to fix the errors you made.<br><br>The second one is to delete the file. Obviously, any custom rules in it will be gone, and in order for permalinks to work again you have to visit <a href="' . admin_url('options-permalink.php') . '">WP Admin - Options - Permalinks</a> and click "Save Changes". This will rebuild the default .htaccess file.<br><br>Third (and preferred) way of fixing is to restore the file from the backup which you\'ll find in the <code>' . $this->get_backup_folder() . '</code> folder. The folder will probably contain multiple backup files. Locate the latest one by looking at the timestamp in the filename. Once located copy the file to <code>' . $this->get_htaccess_path(true) . '</code> and rename it to .htaccess.</p>';
801
 
802
  echo '<b>How to restore .htaccess in case of a non-white-screen error</b>';
803
  echo '<p>Click the "Restore Last Saved Backup" button below the editor and .htaccess will be restored to the version before the last save. Please note that this method only works if the error in the file is logical, not syntactical. For instance, if you banned the wrong IP you can undo. But if you misspelled "RewriteCond" you have to use the method above as the only way to recover is via FTP or cPanel.</p>';
@@ -813,7 +843,7 @@ class WP_Htaccess_Editor {
813
  echo '<textarea cols="70" rows="20" name="newcontent" id="newcontent" aria-describedby="editor-keyboard-trap-help-1 editor-keyboard-trap-help-2 editor-keyboard-trap-help-3 editor-keyboard-trap-help-4">' . esc_textarea($htaccess_content) . '</textarea>';
814
  echo '</div>';
815
 
816
- echo '<p id="wphe-buttons" style="' . ($this->get_dismissed_notices('editor-warning')? '': 'display: none;') .'"><a id="wphe_save_htaccess" href="#" class="button button-primary">Save Changes</a> <a id="wphe_restore_htaccess" href="#" class="button button-secondary">Restore Last Backup</a></p>';
817
 
818
  echo '</form>';
819
  echo '</div>'; // wrap
@@ -825,7 +855,8 @@ class WP_Htaccess_Editor {
825
  *
826
  * @return null
827
  */
828
- static function uninstall() {
 
829
  delete_option('wp-htaccess-editor');
830
  } // uninstall
831
 
@@ -835,7 +866,8 @@ class WP_Htaccess_Editor {
835
  *
836
  * @return null
837
  */
838
- private function __clone() {}
 
839
 
840
 
841
  /**
@@ -843,7 +875,8 @@ class WP_Htaccess_Editor {
843
  *
844
  * @return null
845
  */
846
- private function __sleep() {}
 
847
 
848
 
849
  /**
@@ -851,7 +884,8 @@ class WP_Htaccess_Editor {
851
  *
852
  * @return null
853
  */
854
- private function __wakeup() {}
 
855
  } // WP_Htaccess_Editor class
856
 
857
 
1
  <?php
2
+ /*
3
  Plugin Name: WP Htaccess Editor
4
  Plugin URI: https://wphtaccess.com/
5
  Description: Safe and easy way to edit the .htaccess file directly from WP admin without using FTP.
6
+ Version: 1.60
7
  Author: WebFactory Ltd
8
  Author URI: https://www.webfactoryltd.com/
9
  Text Domain: wp-htaccess-editor
10
+ Network: true
11
 
12
  Copyright 2011 - 2018 Lukenzi (email: lukenzi@gmail.com)
13
  Copyright 2018 - 2019 WebFactory Ltd (email: support@webfactoryltd.com)
33
  }
34
 
35
 
36
+ class WP_Htaccess_Editor
37
+ {
38
  protected static $instance = null;
39
  public $version = 0;
40
  public $plugin_url = '';
49
  *
50
  * @return WP_Htaccess_Editor
51
  */
52
+ static function get_instance()
53
+ {
54
  if (false == is_a(self::$instance, 'WP_Htaccess_Editor')) {
55
  self::$instance = new WP_Htaccess_Editor();
56
  }
64
  *
65
  * @return null
66
  */
67
+ private function __construct()
68
+ {
69
  $this->version = $this->get_plugin_version();
70
  $this->plugin_url = plugin_dir_url(__FILE__);
71
  $this->plugin_basename = plugin_basename(__FILE__);
89
  *
90
  * @return string
91
  */
92
+ function get_plugin_version()
93
+ {
94
  $plugin_data = get_file_data(__FILE__, array('version' => 'Version'), 'plugin');
95
 
96
  return $plugin_data['version'];
104
  *
105
  * @return array
106
  */
107
+ function plugin_action_links($links)
108
+ {
109
  // whole plugin is for admins only
110
  if (false === current_user_can('administrator')) {
111
  return $links;
112
  }
113
 
114
+ $settings_link = '<a href="' . admin_url('options-general.php?page=wp-htaccess-editor') . '" title="' . __('Edit .htaccess file', 'wp-htaccess-editor') . '">' . __('Edit .htaccess file', 'wp-htaccess-editor') . '</a>';
115
 
116
  array_unshift($links, $settings_link);
117
 
127
  *
128
  * @return array
129
  */
130
+ function plugin_meta_links($links, $file)
131
+ {
132
  if ($file !== $this->plugin_basename) {
133
  return $links;
134
  }
150
  *
151
  * @return bool
152
  */
153
+ function is_plugin_page()
154
+ {
155
  $current_screen = get_current_screen();
156
 
157
+ if ($current_screen->id === 'settings_page_wp-htaccess-editor') {
158
  return true;
159
  } else {
160
  return false;
169
  *
170
  * @return string
171
  */
172
+ function admin_footer_text($text_org)
173
+ {
174
  if (false === $this->is_plugin_page()) {
175
  return $text_org;
176
  }
177
 
178
+ $text = '<i><a target="_blank" href="' . $this->generate_web_link('admin_footer') . '">WP Htaccess Editor</a> v' . $this->version . ' by <a href="https://www.webfactoryltd.com/" title="' . __('Visit our site to get more great plugins', 'wp-htaccess-editor') . '" target="_blank">WebFactory Ltd</a>.';
179
  $text .= ' Please <a target="_blank" href="https://wordpress.org/support/plugin/wp-htaccess-editor/reviews/#new-post" title="' . __('Rate the plugin', 'wp-htaccess-editor') . '">' . __('Rate the plugin ★★★★★', 'wp-htaccess-editor') . '</a>.</i> ';
180
 
181
  return $text;
187
  *
188
  * @return null
189
  */
190
+ function load_textdomain()
191
+ {
192
  load_plugin_textdomain('wp-htaccess-editor');
193
  } // load_textdomain
194
 
198
  *
199
  * @return object
200
  */
201
+ private function setup_wp_filesystem()
202
+ {
203
  global $wp_filesystem;
204
 
205
  if (empty($wp_filesystem)) {
217
  *
218
  * @return string
219
  */
220
+ function get_backup_folder()
221
+ {
222
  $folder = trailingslashit(WP_CONTENT_DIR) . trailingslashit($this->backup_folder);
223
 
224
  return $folder;
232
  *
233
  * @return string
234
  */
235
+ function get_htaccess_path($folder_only = false)
236
+ {
237
  if ($folder_only) {
238
  return get_home_path();
239
  } else {
247
  *
248
  * @return string
249
  */
250
+ function get_htaccess_content()
251
+ {
252
  $content = $this->wp_filesystem->get_contents($this->get_htaccess_path());
253
 
254
  return $content;
260
  *
261
  * @return bool
262
  */
263
+ function is_htaccess_writable()
264
+ {
265
  $htaccess_path = $this->get_htaccess_path();
266
 
267
  return $this->wp_filesystem->is_writable($htaccess_path);
273
  *
274
  * @return bool
275
  */
276
+ function is_htaccess_readable()
277
+ {
278
  $htaccess_path = $this->get_htaccess_path();
279
 
280
  return $this->wp_filesystem->is_readable($htaccess_path);
286
  *
287
  * @return array
288
  */
289
+ private function load_options()
290
+ {
291
  $options = get_option('wp-htaccess-editor', array());
292
  $change = false;
293
 
317
  *
318
  * @return array
319
  */
320
+ function get_meta()
321
+ {
322
  return $this->options['meta'];
323
  } // get_meta
324
 
330
  *
331
  * @return bool|array
332
  */
333
+ function get_dismissed_notices($notice_name = '')
334
+ {
335
  $notices = $this->options['dismissed_notices'];
336
 
337
  if (empty($notice_name)) {
353
  *
354
  * @return array
355
  */
356
+ function get_options($option_key = '')
357
+ {
358
  if (empty($option_key)) {
359
  return $this->options['options'];
360
  } else {
375
  *
376
  * @return bool
377
  */
378
+ private function update_options($key, $data)
379
+ {
380
  if (false === in_array($key, array('options', 'meta', 'dismissed_notices'))) {
381
  trigger_error('Unknown option key used in update_options($key, $data) function.', E_USER_ERROR);
382
  return false;
390
 
391
 
392
  /**
393
+ * Add plugin menu entry under Settings menu
394
  *
395
  * @return null
396
  */
397
+ function admin_menu()
398
+ {
399
+ add_options_page(__('WP Htaccess Editor', 'wp-htaccess-editor'), __('WP Htaccess Editor', 'wp-htaccess-editor'), 'administrator', 'wp-htaccess-editor', array($this, 'plugin_page'));
400
  } // admin_menu
401
 
402
 
410
  *
411
  * @return string
412
  */
413
+ function generate_web_link($placement = '', $page = '/', $params = array(), $anchor = '')
414
+ {
415
  $base_url = 'https://wphtaccess.com';
416
 
417
  if ('/' != $page) {
438
  *
439
  * @return null
440
  */
441
+ function ajax_dismiss_notice()
442
+ {
443
  check_ajax_referer('wp-htaccess-editor_dismiss_notice');
444
 
445
  // complete plugin is for admins only
468
  *
469
  * @return bool
470
  */
471
+ function dismiss_notice($notice_name)
472
+ {
473
  if ($this->get_dismissed_notices($notice_name)) {
474
  return false;
475
  } else {
486
  *
487
  * @return array
488
  */
489
+ function get_pointers()
490
+ {
491
  $pointers = array();
492
+ $meta = $this->get_meta();
493
 
494
  // TODO: reformat & prepare for translation
495
+ $pointers['welcome'] = array('target' => '#menu-settings', 'edge' => 'left', 'align' => 'right', 'content' => 'Thank you for using the <b style="font-weight: 700;">WP Htaccess Editor</b> plugin.<br>Open <a href="' . admin_url('options-general.php?page=wp-htaccess-editor') . '">Settings - WP Htaccess Editor</a> to access the editor and start editing the <i>.htaccess</i> file.');
496
+
497
+ if (true === version_compare($meta['first_version'], '1.60', '<')) {
498
+ // TODO: reformat & prepare for translation
499
+ $pointers['menu-relocation'] = array('target' => '#menu-settings', 'edge' => 'left', 'align' => 'right', 'content' => 'We\'ve moved the <b style="font-weight: 700;">WP Htaccess Editor</b> plugin from Tools to the Settings menu. Sorry for the inconvenience. <br>To edit htaccess open <a href="' . admin_url('options-general.php?page=wp-htaccess-editor') . '">Settings - WP Htaccess Editor</a>.');
500
+ }
501
 
502
  return $pointers;
503
  } // get_pointers
510
  *
511
  * @return null
512
  */
513
+ function admin_enqueue_scripts($hook)
514
+ {
515
  // welcome pointer is shown on all pages except WPHE, only to admins, until dismissed
516
  $pointers = $this->get_pointers();
517
  $dismissed_notices = $this->get_dismissed_notices();
522
  }
523
  } // foreach
524
 
525
+ if (current_user_can('administrator') && !empty($pointers) && 'settings_page_wp-htaccess-editor' != $hook) {
526
  $pointers['_nonce_dismiss_pointer'] = wp_create_nonce('wp-htaccess-editor_dismiss_notice');
527
 
528
  wp_enqueue_style('wp-pointer');
533
  }
534
 
535
  // exit early if not on WPHE page
536
+ if ('settings_page_wp-htaccess-editor' != $hook) {
537
  return;
538
  }
539
 
 
540
  $editor_settings['codeEditor'] = wp_enqueue_code_editor(array($this->get_htaccess_path()));
541
  $editor_settings['codeEditor']['codemirror']['mode'] = 'nginx';
542
 
543
+ $js_localize = array(
544
+ 'undocumented_error' => __('An undocumented error has occurred. Please refresh the page and try again.', 'wp-htaccess-editor'),
545
+ 'documented_error' => __('An error has occurred.', 'wp-htaccess-editor'),
546
+ 'plugin_name' => __('WP Htaccess Editor', 'wp-htaccess-editor'),
547
+ 'home_url' => get_home_url(),
548
+ 'settings_url' => admin_url('options-general.php?page=wp-htaccess-editor'),
549
+ 'loading_icon_url' => $this->plugin_url . 'img/loading-icon.png',
550
+ 'cancel_button' => __('Cancel', 'wp-htaccess-editor'),
551
+ 'ok_button' => __('OK', 'wp-htaccess-editor'),
552
+ 'saving' => __('Saving in progress. Please wait.', 'wp-htaccess-editor'),
553
+ 'restoring' => __('Restoring in progress. Please wait.', 'wp-htaccess-editor'),
554
+ 'save_success' => __('Changes have been saved.', 'wp-htaccess-editor'),
555
+ 'restore_message' => __('This will restore the last saved backup of .htaccess. There is NO UNDO.', 'wp-htaccess-editor'),
556
+ 'restore_title' => __('Restore last backup?', 'wp-htaccess-editor'),
557
+ 'restore_button' => __('Restore Last Saved Backup of .htaccess', 'wp-htaccess-editor'),
558
+ 'restore_success' => __('Backup has been successfully restored. Click OK to reload the page.', 'wp-htaccess-editor'),
559
+ 'site_error' => __('There is an error in the .htaccess file and your site is probably no longer accessible.<br><br>DO NOT panic or reload this page. Close this message. First, try the "Restore Last Backup" button. If it doesn\'t work read instruction on this very page on how to restore the site.', 'wp-htaccess-editor'),
560
+ 'nonce_dismiss_notice' => wp_create_nonce('wp-htaccess-editor_dismiss_notice'),
561
+ 'nonce_do_action' => wp_create_nonce('wp-htaccess-editor_do_action'),
562
+ 'cm_settings' => $editor_settings
563
+ );
564
 
565
  wp_enqueue_style('wp-codemirror');
566
  wp_enqueue_style('wp-htaccess-editor', $this->plugin_url . 'css/wp-htaccess-editor.css', array(), $this->version);
575
 
576
  // fix for aggressive plugins that include their CSS files on all pages
577
  wp_dequeue_style('uiStyleSheet');
578
+ wp_dequeue_style('wpcufpnAdmin');
579
+ wp_dequeue_style('unifStyleSheet');
580
  wp_dequeue_style('wpcufpn_codemirror');
581
  wp_dequeue_style('wpcufpn_codemirrorTheme');
582
  wp_dequeue_style('collapse-admin-css');
594
  *
595
  * @return null
596
  */
597
+ function ajax_do_action()
598
+ {
599
  check_ajax_referer('wp-htaccess-editor_do_action');
600
 
601
  if (false === current_user_can('administrator')) {
642
  *
643
  * @return bool
644
  */
645
+ function write_htaccess($new_content)
646
+ {
647
  $htaccess_path = $this->get_htaccess_path();
648
  $result = $this->wp_filesystem->put_contents($htaccess_path, $new_content);
649
  @clearstatcache();
653
  $meta['edits_count']++;
654
  $this->update_options('meta', $meta);
655
  return true;
656
+ } else {
657
  return false;
658
  }
659
  } // write_htaccess
667
  *
668
  * @return bool
669
  */
670
+ function create_htaccess_backup($db_save = true, $file_save = true)
671
+ {
672
  $success = false;
673
  $orig_path = $this->get_htaccess_path();
674
 
697
 
698
  if ($success) {
699
  return true;
700
+ } else {
701
  return false;
702
  }
703
  } // create_htaccess_backup
708
  *
709
  * @return bool
710
  */
711
+ function create_secure_backup_folder()
712
+ {
713
  @clearstatcache();
714
  $secure_path = $this->get_backup_folder() . '.htaccess';
715
  $secure_text = trim('
730
  return true;
731
  } else {
732
  $write = $this->wp_filesystem->put_contents($secure_path, $secure_text);
733
+ if ($write) {
734
  return true;
735
  } else {
736
  return false;
744
  *
745
  * @return bool
746
  */
747
+ function restore_db_backup()
748
+ {
749
  $htaccess_path = $this->get_htaccess_path();
750
 
751
  $backup_contents = $this->get_options('last_backup');
774
  *
775
  * @return null
776
  */
777
+ function plugin_page()
778
+ {
779
  $notice_shown = false;
780
  $meta = $this->get_meta();
 
 
781
  $htaccess_content = $this->get_htaccess_content();
782
 
783
  // double check for admin priv
788
  settings_errors();
789
  echo '<div class="wrap">';
790
  echo '<h1><img src="' . $this->plugin_url . 'img/wp-htaccess-editor-logo.png" alt="' . __('WP Htaccess Editor', 'wp-htaccess-editor') . '" title="' . __('WP Htaccess Editor', 'wp-htaccess-editor') . '"></h1>';
791
+ echo '<form id="wp-htaccess-editor-form" action="' . admin_url('options-general.php?page=wp-htaccess-editor') . '" method="post" autocomplete="off">';
792
 
793
  // TODO: properly mark for translation
794
  if (false === $this->is_htaccess_readable()) {
808
  $notice_shown = true;
809
  }
810
 
811
+ // ask for rating after first save
812
+ if ($meta['edits_count'] > 0 && false === $notice_shown && false == $this->get_dismissed_notices('rate')) {
 
 
 
 
 
 
 
 
813
  echo '<div class="card notice-wrapper">';
814
  echo '<h2>' . __('Please help us keep the plugin free &amp; up-to-date', 'wp-htaccess-editor') . '</h2>';
815
  echo '<p>' . __('If you use &amp; enjoy WP Htaccess Editor, <b>please rate it on WordPress.org</b>. It only takes a second and helps us keep the plugin free and maintained. Thank you!', 'wp-htaccess-editor') . '</p>';
827
  echo 'For more details about .htaccess syntax and examples, please visit the <a href="http://httpd.apache.org/docs/current/howto/htaccess.html" target="_blank">official Apache Tutorial</a>.</p>';
828
 
829
  echo '<b>How to restore the site in case of error 500 or white screen caused by .htaccess</b>';
830
+ echo '<p>Do not panic. No data is lost, and your site will be up again in minutes. FTP to your site or open the server\'s control panel such as cPanel to locate the .htaccess file in <code>' . $this->get_htaccess_path() . '</code>. Once you find the file there are several options to restore the site.<br><br>The first option is to edit the file and fix the error(s) you made.<br><br>The second one is to delete the file. Obviously, any custom rules in it will be gone, and in order for permalinks to work again you have to visit <a href="' . admin_url('options-permalink.php') . '">WP Admin - Options - Permalinks</a> and click "Save Changes". This will rebuild the default .htaccess file.<br><br>Third (and preferred) way of fixing is to restore the file from the backup which you\'ll find in the <code>' . $this->get_backup_folder() . '</code> folder. The folder will probably contain multiple backup files. Locate the latest one by looking at the timestamp in the filename. Once located copy the file to <code>' . $this->get_htaccess_path(true) . '</code> and rename it to .htaccess.</p>';
831
 
832
  echo '<b>How to restore .htaccess in case of a non-white-screen error</b>';
833
  echo '<p>Click the "Restore Last Saved Backup" button below the editor and .htaccess will be restored to the version before the last save. Please note that this method only works if the error in the file is logical, not syntactical. For instance, if you banned the wrong IP you can undo. But if you misspelled "RewriteCond" you have to use the method above as the only way to recover is via FTP or cPanel.</p>';
843
  echo '<textarea cols="70" rows="20" name="newcontent" id="newcontent" aria-describedby="editor-keyboard-trap-help-1 editor-keyboard-trap-help-2 editor-keyboard-trap-help-3 editor-keyboard-trap-help-4">' . esc_textarea($htaccess_content) . '</textarea>';
844
  echo '</div>';
845
 
846
+ echo '<p id="wphe-buttons" style="' . ($this->get_dismissed_notices('editor-warning') ? '' : 'display: none;') . '"><a id="wphe_save_htaccess" href="#" class="button button-primary">Save Changes</a> <a id="wphe_restore_htaccess" href="#" class="button button-secondary">Restore Last Backup</a></p>';
847
 
848
  echo '</form>';
849
  echo '</div>'; // wrap
855
  *
856
  * @return null
857
  */
858
+ static function uninstall()
859
+ {
860
  delete_option('wp-htaccess-editor');
861
  } // uninstall
862
 
866
  *
867
  * @return null
868
  */
869
+ private function __clone()
870
+ { }
871
 
872
 
873
  /**
875
  *
876
  * @return null
877
  */
878
+ private function __sleep()
879
+ { }
880
 
881
 
882
  /**
884
  *
885
  * @return null
886
  */
887
+ private function __wakeup()
888
+ { }
889
  } // WP_Htaccess_Editor class
890
 
891