PluginProbe
Stream – Activity Log & Audit Trail / 3.2.2
Stream – Activity Log & Audit Trail v3.2.2
4.4.0 4.3.0 4.2.2 4.2.1 trunk 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.1 3.1.1 3.10.0 3.2.0 3.2.1 3.2.2 3.2.3 All 50 releases
stream / connectors / class-connector-editor.php

class-connector-editor.php in Stream – Activity Log & Audit Trail 3.2.2, at connectors/class-connector-editor.php

331 lines 7.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace WP_Stream;
3
4 class Connector_Editor extends Connector {
5 /**
6 * Connector slug
7 *
8 * @var string
9 */
10 public $name = 'editor';
11
12 /**
13 * Actions registered for this connector
14 *
15 * @var array
16 */
17 public $actions = array();
18
19 /**
20 * Actions registered for this connector
21 *
22 * @var array
23 */
24 private $edited_file = array();
25
26 /**
27 * Register connector in the WP Frontend
28 *
29 * @var bool
30 */
31 public $register_frontend = false;
32
33 /**
34 * Register all context hooks
35 *
36 * @return void
37 */
38 public function register() {
39 parent::register();
40 add_action( 'load-theme-editor.php', array( $this, 'get_edition_data' ) );
41 add_action( 'load-plugin-editor.php', array( $this, 'get_edition_data' ) );
42 add_filter( 'wp_redirect', array( $this, 'log_changes' ) );
43 }
44
45 /**
46 * Return translated connector label
47 *
48 * @return string Translated connector label
49 */
50 public function get_label() {
51 return esc_html__( 'Editor', 'stream' );
52 }
53
54 /**
55 * Return translated action labels
56 *
57 * @return array Action label translations
58 */
59 public function get_action_labels() {
60 return array(
61 'updated' => esc_html__( 'Updated', 'stream' ),
62 );
63 }
64
65 /**
66 * Return translated context labels
67 *
68 * @return array Context label translations
69 */
70 public function get_context_labels() {
71 /**
72 * Filter available context labels for the Editor connector
73 *
74 * @return array Array of context slugs and their translated labels
75 */
76 return apply_filters(
77 'wp_stream_editor_context_labels',
78 array(
79 'themes' => esc_html__( 'Themes', 'stream' ),
80 'plugins' => esc_html__( 'Plugins', 'stream' ),
81 )
82 );
83 }
84
85 /**
86 * Get the context based on wp_redirect location
87 *
88 * @param string $location The URL of the redirect
89 * @return string Context slug
90 */
91 public function get_context( $location ) {
92 $context = null;
93
94 if ( false !== strpos( $location, 'theme-editor.php' ) ) {
95 $context = 'themes';
96 }
97
98 if ( false !== strpos( $location, 'plugin-editor.php' ) ) {
99 $context = 'plugins';
100 }
101
102 /**
103 * Filter available contexts for the Editor connector
104 *
105 * @param string $context Context slug
106 * @param string $location The URL of the redirect
107 * @return string Context slug
108 */
109 return apply_filters( 'wp_stream_editor_context', $context, $location );
110 }
111
112 /**
113 * Get the message format for file updates
114 *
115 * @return string Translated string
116 */
117 public function get_message() {
118 return _x(
119 '"%1$s" in "%2$s" updated',
120 '1: File name, 2: Theme/plugin name',
121 'stream'
122 );
123 }
124
125 /**
126 * Add action links to Stream drop row in admin list screen
127 *
128 * @filter wp_stream_action_links_{connector}
129 *
130 * @param array $links Previous links registered
131 * @param object $record Stream record
132 *
133 * @return array Action links
134 */
135 public function action_links( $links, $record ) {
136 if ( current_user_can( 'edit_theme_options' ) ) {
137 $file_name = $record->get_meta( 'file', true );
138 $file_path = $record->get_meta( 'file_path', true );
139
140 if ( ! empty( $file_name ) && ! empty( $file_path ) ) {
141 $theme_slug = $record->get_meta( 'theme_slug', true );
142 $plugin_slug = $record->get_meta( 'plugin_slug', true );
143 $theme_exists = ( ! empty( $theme_slug ) && file_exists( $file_path ) );
144 $plugin_exists = ( ! empty( $plugin_slug ) && file_exists( $file_path ) );
145
146 if ( $theme_exists ) {
147 $links[ esc_html__( 'Edit File', 'stream' ) ] = add_query_arg(
148 array(
149 'theme' => urlencode( $theme_slug ),
150 'file' => urlencode( $file_name ),
151 ),
152 self_admin_url( 'theme-editor.php' )
153 );
154
155 $links[ esc_html__( 'Theme Details', 'stream' ) ] = add_query_arg(
156 array(
157 'theme' => urlencode( $theme_slug ),
158 ),
159 self_admin_url( 'themes.php' )
160 );
161 }
162
163 if ( $plugin_exists ) {
164 $links[ esc_html__( 'Edit File', 'stream' ) ] = add_query_arg(
165 array(
166 'plugin' => urlencode( $plugin_slug ),
167 'file' => urlencode( str_ireplace( trailingslashit( WP_PLUGIN_DIR ), '', $file_path ) ),
168 ),
169 self_admin_url( 'plugin-editor.php' )
170 );
171 }
172 }
173 }
174
175 return $links;
176 }
177
178 /**
179 * Retrieves data submitted on the screen, and prepares it for the appropriate context type
180 *
181 * @action load-theme-editor.php
182 * @action load-plugin-editor.php
183 */
184 public function get_edition_data() {
185 if (
186 (
187 isset( $_SERVER['REQUEST_METHOD'] )
188 &&
189 'POST' !== esc_attr( $_SERVER['REQUEST_METHOD'] )
190 )
191 ||
192 'update' !== wp_stream_filter_input( INPUT_POST, 'action' )
193 ) {
194 return;
195 }
196
197 if ( $slug = wp_stream_filter_input( INPUT_POST, 'theme' ) ) {
198 $this->edited_file = $this->get_theme_data( $slug );
199 }
200
201 if ( $slug = wp_stream_filter_input( INPUT_POST, 'plugin' ) ) {
202 $this->edited_file = $this->get_plugin_data( $slug );
203 }
204 }
205
206 /**
207 * Retrieve theme data needed for the log message
208 *
209 * @param string $slug The theme slug (e.g. twentyfourteen)
210 *
211 * @return mixed $output Compacted variables
212 */
213 public function get_theme_data( $slug ) {
214 $theme = wp_get_theme( $slug );
215
216 if ( ! $theme->exists() || ( $theme->errors() && 'theme_no_stylesheet' === $theme->errors()->get_error_code() ) ) {
217 return false;
218 }
219
220 $allowed_files = $theme->get_files( 'php', 1 );
221 $style_files = $theme->get_files( 'css' );
222 $file = wp_stream_filter_input( INPUT_POST, 'file' );
223
224 $allowed_files['style.css'] = $style_files['style.css'];
225
226 if ( empty( $file ) ) {
227 $file_name = 'style.css';
228 $file_path = $allowed_files['style.css'];
229 } else {
230 $file_name = $file;
231 $file_path = sprintf( '%s/%s', $theme->get_stylesheet_directory(), $file_name );
232 }
233
234 //TODO: phpcs fix
235 $file_contents_before = file_get_contents( $file_path );
236
237 $name = $theme->get( 'Name' );
238
239 $output = compact(
240 'file_name',
241 'file_path',
242 'file_contents_before',
243 'slug',
244 'name'
245 );
246
247 return $output;
248 }
249
250 /**
251 * Retrieve plugin data needed for the log message
252 *
253 * @param string $slug The plugin file base name (e.g. akismet/akismet.php)
254 * @return mixed $output Compacted variables
255 */
256 public function get_plugin_data( $slug ) {
257 $base = null;
258 $name = null;
259 $slug = current( explode( '/', $slug ) );
260 $file_name = wp_stream_filter_input( INPUT_POST, 'file' );
261 $file_path = WP_PLUGIN_DIR . '/' . $file_name;
262
263 //TODO: phpcs fix
264 $file_contents_before = file_get_contents( $file_path );
265
266 $plugins = get_plugins();
267
268 foreach ( $plugins as $key => $plugin_data ) {
269 if ( 0 === strpos( $key, $slug ) ) {
270 $base = $key;
271 $name = $plugin_data['Name'];
272 break;
273 }
274 }
275
276 $file_name = str_ireplace( trailingslashit( $slug ), '', $file_name );
277 $slug = ! empty( $base ) ? $base : $slug;
278
279 $output = compact(
280 'file_name',
281 'file_path',
282 'file_contents_before',
283 'slug',
284 'name'
285 );
286
287 return $output;
288 }
289
290 /**
291 * @filter wp_redirect
292 */
293 public function log_changes( $location ) {
294 if ( ! empty( $this->edited_file ) ) {
295 // TODO: phpcs fix
296 if ( file_get_contents( $this->edited_file['file_path'] ) !== $this->edited_file['file_contents_before'] ) {
297 $context = $this->get_context( $location );
298
299 switch ( $context ) {
300 case 'themes':
301 $name_key = 'theme_name';
302 $slug_key = 'theme_slug';
303 break;
304 case 'plugins':
305 $name_key = 'plugin_name';
306 $slug_key = 'plugin_slug';
307 break;
308 default:
309 $name_key = 'name';
310 $slug_key = 'slug';
311 }
312
313 $this->log(
314 $this->get_message(),
315 array(
316 'file' => (string) $this->edited_file['file_name'],
317 $name_key => (string) $this->edited_file['name'],
318 $slug_key => (string) $this->edited_file['slug'],
319 'file_path' => (string) $this->edited_file['file_path'],
320 ),
321 null,
322 $context,
323 'updated'
324 );
325 }
326 }
327
328 return $location;
329 }
330 }
331