PluginProbe
Code Snippets / 3.7.0
Code Snippets v3.7.0
3.10.2 3.10.1 3.10.0 3.10.0-beta.2 3.10.0-beta.1 4.0.0-beta.1 3.9.6 trunk 2.10.0 2.10.1 2.12.0 2.12.1 2.13.0 2.13.1 2.13.2 2.13.3 2.14.0 2.14.1 2.14.2 2.14.3 2.14.4 2.14.5 2.14.6 3.0.0 3.0.1 All 64 releases
code-snippets / php / evaluation / class-evaluate-functions.php

class-evaluate-functions.php in Code Snippets 3.7.0, at php/evaluation/class-evaluate-functions.php

143 lines 4.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Evaluation;
4
5 use Code_Snippets\DB;
6 use Code_Snippets\REST_API\Snippets_REST_Controller;
7 use function Code_Snippets\clean_active_snippets_cache;
8 use function Code_Snippets\clean_snippets_cache;
9 use function Code_Snippets\execute_snippet;
10
11 /**
12 * Class for evaluating functions snippets.
13 *
14 * @package Code_Snippets
15 */
16 class Evaluate_Functions {
17
18 /**
19 * Database class.
20 *
21 * @var DB
22 */
23 private DB $db;
24
25 /**
26 * Class constructor.
27 *
28 * @param DB $db Database class instance.
29 */
30 public function __construct( DB $db ) {
31 $this->db = $db;
32 add_action( 'plugins_loaded', [ $this, 'evaluate_early' ], 1 );
33 }
34
35 /**
36 * Retrieve details about the currently edited snippet, if any.
37 *
38 * @return ?array{id: int, table: string}
39 */
40 private function get_currently_editing_snippet(): ?array {
41 if ( wp_is_json_request() && ! empty( $_SERVER['REQUEST_URI'] ) ) {
42 $url = wp_parse_url( esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
43
44 if ( isset( $url['path'] ) && false !== strpos( $url['path'], Snippets_REST_Controller::get_prefixed_base_route() ) ) {
45 $path_parts = explode( '/', $url['path'] );
46 $edit_id = intval( end( $path_parts ) );
47
48 if ( ! empty( $url['query'] ) ) {
49 wp_parse_str( $url['query'], $path_params );
50 $edit_table = isset( $path_params['network'] ) && rest_sanitize_boolean( $path_params['network'] )
51 ? $this->db->ms_table
52 : $this->db->table;
53 }
54
55 return [
56 'id' => $edit_id,
57 'table' => $edit_table ?? $this->db->table,
58 ];
59 }
60 }
61
62 return null;
63 }
64
65 /**
66 * Check if the plugin is running in safe mode.
67 *
68 * @return bool
69 *
70 * @noinspection PhpUndefinedConstantInspection
71 */
72 public function is_safe_mode_active(): bool {
73 return ( defined( 'CODE_SNIPPETS_SAFE_MODE' ) && CODE_SNIPPETS_SAFE_MODE ) ||
74 ! apply_filters( 'code_snippets/execute_snippets', true );
75 }
76
77 /**
78 * Quickly deactivate a snippet with minimal overhead.
79 *
80 * @param int $snippet_id ID of the snippet to deactivate.
81 * @param string $table_name Name of the table where the snippet is stored.
82 *
83 * @return void
84 */
85 private function quick_deactivate_snippet( int $snippet_id, string $table_name ) {
86 global $wpdb;
87
88 $active_shared_ids = get_option( 'active_shared_network_snippets', [] );
89 $active_shared_ids = is_array( $active_shared_ids )
90 ? array_map( 'intval', $active_shared_ids )
91 : [];
92
93 if ( $table_name === $this->db->ms_table && in_array( $snippet_id, $active_shared_ids, true ) ) {
94 unset( $active_shared_ids[ array_search( $snippet_id, $active_shared_ids, true ) ] );
95 $active_shared_ids = array_values( $active_shared_ids );
96 update_option( 'active_shared_network_snippets', $active_shared_ids );
97 clean_active_snippets_cache( $table_name );
98 } else {
99 $wpdb->update(
100 $table_name,
101 [ 'active' => '0' ],
102 [ 'id' => $snippet_id ],
103 [ '%d' ],
104 [ '%d' ]
105 );
106 clean_snippets_cache( $table_name );
107 }
108 }
109
110 /**
111 * Evaluate applicable active snippets as early as possible.
112 *
113 * @return bool True if snippets were evaluated, false if safe mode is active.
114 */
115 public function evaluate_early(): bool {
116 if ( $this->is_safe_mode_active() ) {
117 return false;
118 }
119
120 $scopes = [ 'global', 'single-use', is_admin() ? 'admin' : 'front-end' ];
121 $active_snippets = $this->db->fetch_active_snippets( $scopes );
122 $edit_snippet = $this->get_currently_editing_snippet();
123
124 foreach ( $active_snippets as $snippet ) {
125 $snippet_id = $snippet['id'];
126 $code = $snippet['code'];
127 $table_name = $snippet['table'];
128
129 // If the snippet is a single-use snippet, deactivate it before execution to ensure that the process always happens.
130 if ( 'single-use' === $snippet['scope'] ) {
131 $this->quick_deactivate_snippet( $snippet_id, $table_name );
132 }
133
134 if ( apply_filters( 'code_snippets/allow_execute_snippet', true, $snippet_id, $table_name ) &&
135 ( is_null( $edit_snippet ) || $edit_snippet['id'] !== $snippet_id || $edit_snippet['table'] !== $table_name ) ) {
136 execute_snippet( $code, $snippet_id );
137 }
138 }
139
140 return true;
141 }
142 }
143