PluginProbe
Code Snippets / trunk
Code Snippets vtrunk
4.0.0-beta.2 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 All 65 releases
code-snippets / php / Core / Upgrader.php

Upgrader.php in Code Snippets trunk, at php/Core/Upgrader.php

268 lines 8.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Code_Snippets\Core;
4
5 use Code_Snippets\Client\Welcome_Client;
6 use Code_Snippets\Model\Snippet;
7 use WP_User;
8 use function Code_Snippets\clean_snippets_cache;
9 use function Code_Snippets\flush_versioned_cache_groups;
10 use function Code_Snippets\code_snippets;
11 use function Code_Snippets\save_snippet;
12
13 /**
14 * Manages upgrade tasks such as deleting and updating options
15 */
16 class Upgrader {
17
18 /**
19 * Option recording the plugin version that last wrote to the cache.
20 */
21 private const CACHE_VERSION_OPTION = 'code_snippets_cache_version';
22
23 /**
24 * Instance of database class
25 *
26 * @var DB
27 */
28 private DB $db;
29
30 /**
31 * The current plugin version number
32 *
33 * @var string
34 */
35 private string $current_version;
36
37 /**
38 * Class constructor
39 *
40 * @param string $version Current plugin version.
41 * @param DB $db Instance of database class.
42 */
43 public function __construct( string $version, DB $db ) {
44 $this->db = $db;
45 $this->current_version = $version;
46
47 add_action( 'plugins_loaded', [ $this, 'run' ], 0 );
48 }
49
50 /**
51 * Run the upgrade functions
52 */
53 public function run() {
54 $this->handle_version_change();
55
56 // Always run multisite upgrades, even if not on the main site, as sub-sites depend on the network snippet table.
57 if ( is_multisite() ) {
58 $this->do_multisite_upgrades();
59 }
60
61 $this->do_site_upgrades();
62 }
63
64 /**
65 * Discard cached data belonging to a different version of the plugin.
66 *
67 * The do_site_upgrades() method only acts when the version has gone up, so
68 * it never fires on a rollback. Cached data has to be dealt with in both
69 * directions, so it is tracked separately here.
70 *
71 * A dedicated option is used rather than the one that method maintains,
72 * because that option is left untouched on a downgrade, which would leave
73 * this flushing on every request for as long as the older version ran.
74 *
75 * @return void
76 */
77 private function handle_version_change(): void {
78 $previous_version = (string) get_option( self::CACHE_VERSION_OPTION, '' );
79
80 if ( $previous_version === $this->current_version ) {
81 return;
82 }
83
84 // Recorded before flushing so that a cache backend which cannot flush
85 // groups does not leave this repeating on every request.
86 update_option( self::CACHE_VERSION_OPTION, $this->current_version, false );
87
88 flush_versioned_cache_groups( $previous_version );
89 }
90
91 /**
92 * Perform upgrades for the current site
93 */
94 private function do_site_upgrades() {
95 $table_name = $this->db->table;
96 $prev_version = get_option( 'code_snippets_version' );
97
98 // Do nothing if the plugin has not just been updated or installed.
99 if ( ! version_compare( $prev_version, $this->current_version, '<' ) ) {
100 return;
101 }
102
103 // Update the plugin version stored in the database.
104 $updated = update_option( 'code_snippets_version', $this->current_version );
105
106 if ( ! $updated ) {
107 return; // Bail if the data was not successfully saved to prevent this process from repeating.
108 }
109
110 $this->db->create_table( $table_name );
111
112 // Remove outdated user meta.
113 if ( version_compare( $prev_version, '2.14.1', '<' ) ) {
114 global $wpdb;
115
116 $prefix = $wpdb->get_blog_prefix();
117 $menu_slug = code_snippets()->get_menu_slug();
118 $option_name = "{$prefix}managetoplevel_page_{$menu_slug}columnshidden";
119
120 // Loop through each user ID and remove all matching user meta.
121 foreach ( get_users( array( 'fields' => 'ID' ) ) as $user_id ) {
122 delete_metadata( 'user', $user_id, $option_name, '', true );
123 }
124 }
125
126 // Update the scope column of the database.
127 if ( version_compare( $prev_version, '2.10.0', '<' ) ) {
128 $this->migrate_scope_data( $table_name );
129 }
130
131 // Custom capabilities were removed after version 2.9.5.
132 if ( version_compare( $prev_version, '2.9.5', '<=' ) ) {
133 $role = get_role( apply_filters( 'code_snippets_role', 'administrator' ) );
134 $role->remove_cap( apply_filters( 'code_snippets_cap', 'manage_snippets' ) );
135 }
136
137 if ( false === $prev_version ) {
138 add_action( 'init', [ $this, 'create_sample_content' ] );
139 }
140
141 clean_snippets_cache( $table_name );
142 Welcome_Client::clear_cache();
143 }
144
145 /**
146 * Create example snippets.
147 *
148 * As this uses translation functions, this should not be called earlier than 'init'.
149 *
150 * @return void
151 */
152 public function create_sample_content() {
153 if ( apply_filters( 'code_snippets/create_sample_content', true ) ) {
154 $sample_snippets = $this->get_sample_content();
155 foreach ( $sample_snippets as $sample_snippet ) {
156 save_snippet( $sample_snippet );
157 }
158 }
159 }
160
161 /**
162 * Perform multisite-only upgrades
163 */
164 private function do_multisite_upgrades() {
165 $table_name = $this->db->ms_table;
166 $prev_version = get_site_option( 'code_snippets_version' );
167
168 // Do nothing if the plugin has not been updated or installed.
169 if ( ! version_compare( $prev_version, $this->current_version, '<' ) ) {
170 return;
171 }
172
173 // Always attempt to create or upgrade the database tables.
174 $this->db->create_table( $table_name );
175
176 // Update the plugin version stored in the database.
177 update_site_option( 'code_snippets_version', $this->current_version );
178
179 // Update the scope column of the database.
180 if ( version_compare( $prev_version, '2.10.0', '<' ) ) {
181 $this->migrate_scope_data( $table_name );
182 }
183
184 // Custom capabilities were removed after version 2.9.5.
185 if ( version_compare( $prev_version, '2.9.5', '<=' ) ) {
186 $network_cap = apply_filters( 'code_snippets_network_cap', 'manage_network_snippets' );
187
188 foreach ( get_super_admins() as $admin ) {
189 $user = new WP_User( 0, $admin );
190 $user->remove_cap( $network_cap );
191 }
192 }
193
194 clean_snippets_cache( $table_name );
195 }
196
197 /**
198 * Migrate data from the old integer method of storing scopes to the new string method
199 *
200 * @param string $table_name Name of database table.
201 */
202 private function migrate_scope_data( string $table_name ) {
203 global $wpdb;
204
205 $scopes = array(
206 0 => 'global',
207 1 => 'admin',
208 2 => 'front-end',
209 );
210
211 foreach ( $scopes as $scope_number => $scope_name ) {
212 // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching, will flush at end of process.
213 $wpdb->query(
214 $wpdb->prepare(
215 "UPDATE $table_name SET scope = %s WHERE scope = %d",
216 $scope_name,
217 $scope_number
218 )
219 );
220 }
221 }
222
223 /**
224 * Build a collection of sample snippets for new users to try out.
225 *
226 * @return Snippet[] List of Snippet objects.
227 */
228 private function get_sample_content(): array {
229 $tag = "\n\n" . esc_html__( 'This is a sample snippet. Feel free to use it, edit it, or remove it.', 'code-snippets' );
230
231 $snippets_data = array(
232 array(
233 'name' => esc_html__( 'Make upload filenames lowercase', 'code-snippets' ),
234 'code' => "add_filter( 'sanitize_file_name', 'mb_strtolower' );",
235 'desc' => esc_html__( 'Makes sure that image and file uploads have lowercase filenames.', 'code-snippets' ) . $tag,
236 'tags' => array( 'sample', 'media' ),
237 ),
238 array(
239 'name' => esc_html__( 'Disable admin bar', 'code-snippets' ),
240 'code' => "add_action( 'wp', function () {\n\tif ( ! current_user_can( 'manage_options' ) ) {\n\t\tshow_admin_bar( false );\n\t}\n} );",
241 'desc' => esc_html__( 'Turns off the WordPress admin bar for everyone except administrators.', 'code-snippets' ) . $tag,
242 'tags' => array( 'sample', 'admin-bar' ),
243 'scope' => 'front-end',
244 ),
245 array(
246 'name' => esc_html__( 'Allow smilies', 'code-snippets' ),
247 'code' => "add_filter( 'widget_text', 'convert_smilies' );\nadd_filter( 'the_title', 'convert_smilies' );\nadd_filter( 'wp_title', 'convert_smilies' );\nadd_filter( 'get_bloginfo', 'convert_smilies' );",
248 'desc' => esc_html__( 'Allows smiley conversion in obscure places.', 'code-snippets' ) . $tag,
249 'tags' => array( 'sample' ),
250 ),
251 array(
252 'name' => esc_html__( 'Current year', 'code-snippets' ),
253 'code' => "<?php echo date( 'Y' ); ?>",
254 'desc' => esc_html__( 'Shortcode for inserting the current year into a post or page..', 'code-snippets' ) . $tag,
255 'tags' => array( 'sample', 'dates' ),
256 'scope' => 'content',
257 ),
258 );
259
260 return array_map(
261 function ( $snippet_data ) {
262 return new Snippet( $snippet_data );
263 },
264 $snippets_data
265 );
266 }
267 }
268