PluginProbe
WpStream – Live Streaming, Video on Demand, Pay Per View / trunk
WpStream – Live Streaming, Video on Demand, Pay Per View vtrunk
4.14.0 4.13.2 4.13.1 4.13 4.12.5 4.12.4 4.12.3 4.12.2 4.12.1 4.12 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9 4.5 4.5.1 4.5.11 4.5.11.1 4.5.11.2 4.5.11.4 4.5.11.5 4.5.11.6 4.5.12 All 180 releases
wpstream / uninstall.php

uninstall.php in WpStream – Live Streaming, Video on Demand, Pay Per View trunk, at uninstall.php

170 lines 6.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Fired when the plugin is uninstalled (deleted from the Plugins screen).
5 *
6 * This is the plugin's single place for permanent data removal — the
7 * deactivator intentionally preserves the account connection (issue #112),
8 * so credentials/tokens are cleaned up ONLY here. WordPress runs this file
9 * on its own, without loading the plugin, so only core WP functions may be
10 * used below.
11 *
12 * Scope: plugin-owned options, cached data, user meta, scheduled events and
13 * generated Streamify files are removed. WpStream content is preserved unless
14 * the site explicitly opts in to deleting it.
15 *
16 * @link http://wpstream.net
17 * @since 3.0.1
18 *
19 * @package Wpstream
20 */
21
22 // If uninstall not called from WordPress, then exit.
23 // WP_UNINSTALL_PLUGIN is only defined when WordPress runs this file through the
24 // official uninstall routine; its absence means the file was reached directly
25 // (e.g. a direct HTTP request), so we abort to prevent arbitrary execution.
26 if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
27 // Not a legitimate uninstall context — stop immediately.
28 exit;
29 }
30
31 global $wpdb;
32
33 /**
34 * Remove all WpStream-owned data from the current site's tables.
35 *
36 * The current-site seam is intentional: switch_to_blog() changes $wpdb's site
37 * tables, allowing the same cleanup implementation to serve single-site and
38 * multisite installations without separate inventories.
39 */
40 $wpstream_cleanup_current_site = static function () use ( $wpdb ) {
41 // Read the destructive preference before the wpstream_* option sweep.
42 $wpstream_delete_content_option = get_option( 'wpstream_delete_content_on_uninstall', 'no' );
43 $wpstream_delete_content = in_array(
44 $wpstream_delete_content_option,
45 array( true, 1, '1', 'yes' ),
46 true
47 );
48
49 // Credentials and tokens are explicitly removed even if a later bulk query
50 // fails, because plaintext secrets must never outlive the plugin.
51 delete_option( 'wpstream_api_key' );
52 delete_option( 'wpstream_api_secret_key' );
53 delete_option( 'wpstream_api_username' );
54 delete_option( 'wpstream_api_password' );
55 delete_option( 'wpstream_current_token' );
56 delete_option( 'wpstream_token_expire' );
57 // Clean residual pre-TASK-31 names if migration never had a chance to run.
58 delete_option( 'wp_estate_curent_token' );
59 delete_option( 'wp_estate_token_expire' );
60 delete_transient( 'wpstream_token_api' );
61 delete_transient( 'wpstream_token_request_30' );
62
63 wp_clear_scheduled_hook( 'wpstream_log_cleanup' );
64 wp_clear_scheduled_hook( 'wpstreamify_cleanup_event' );
65
66 // Remove dynamic plugin options that cannot be enumerated safely. Escaping
67 // underscores prevents SQL LIKE from broadening the ownership prefixes.
68 $wpstream_option_patterns = array(
69 $wpdb->esc_like( 'wpstream_' ) . '%',
70 $wpdb->esc_like( 'wp_estate_' ) . '%',
71 $wpdb->esc_like( 'wp_stream_' ) . '%',
72 $wpdb->esc_like( '_transient_free_event_streamName_' ) . '%',
73 $wpdb->esc_like( '_transient_timeout_free_event_streamName_' ) . '%',
74 $wpdb->esc_like( '_transient_paid_event_streamName_' ) . '%',
75 $wpdb->esc_like( '_transient_timeout_paid_event_streamName_' ) . '%',
76 $wpdb->esc_like( '_transient_wpstream_' ) . '%',
77 $wpdb->esc_like( '_transient_timeout_wpstream_' ) . '%',
78 $wpdb->esc_like( '_transient_' ) . '%' . $wpdb->esc_like( '_api20_streamName' ),
79 $wpdb->esc_like( '_transient_timeout_' ) . '%' . $wpdb->esc_like( '_api20_streamName' ),
80 $wpdb->esc_like( '_transient_vod_decryption_key_index_' ) . '%',
81 $wpdb->esc_like( '_transient_timeout_vod_decryption_key_index_' ) . '%',
82 $wpdb->esc_like( '_transient_paid_vod_key_index_' ) . '%',
83 $wpdb->esc_like( '_transient_timeout_paid_vod_key_index_' ) . '%',
84 $wpdb->esc_like( '_transient_event_data_to_return_' ) . '%',
85 $wpdb->esc_like( '_transient_timeout_event_data_to_return_' ) . '%',
86 $wpdb->esc_like( '_transient_server_id_to_return_' ) . '%',
87 $wpdb->esc_like( '_transient_timeout_server_id_to_return_' ) . '%',
88 );
89 $wpstream_option_conditions = implode(
90 ' OR ',
91 array_fill( 0, count( $wpstream_option_patterns ), 'option_name LIKE %s' )
92 );
93 $wpdb->query(
94 $wpdb->prepare(
95 "DELETE FROM {$wpdb->options} WHERE {$wpstream_option_conditions}",
96 $wpstream_option_patterns
97 )
98 );
99
100 // User-specific state is normally prefixed; the BuddyBoss integration also
101 // shipped one legacy misspelled key which remains plugin-owned.
102 $wpstream_usermeta_patterns = array(
103 $wpdb->esc_like( 'wpstream_' ) . '%',
104 $wpdb->esc_like( 'budyboss_selected_channel' ),
105 );
106 $wpdb->query(
107 $wpdb->prepare(
108 "DELETE FROM {$wpdb->usermeta} WHERE meta_key LIKE %s OR meta_key LIKE %s",
109 $wpstream_usermeta_patterns
110 )
111 );
112
113 // Authored content is valuable, so delete it only for this site's opt-in.
114 if ( $wpstream_delete_content ) {
115 $wpstream_content_ids = get_posts(
116 array(
117 'post_type' => array( 'wpstream_product', 'wpstream_product_vod', 'wpstream_bundles' ),
118 'post_status' => 'any',
119 'numberposts' => -1,
120 'fields' => 'ids',
121 'suppress_filters' => true,
122 )
123 );
124
125 foreach ( $wpstream_content_ids as $wpstream_content_id ) {
126 wp_delete_post( (int) $wpstream_content_id, true );
127 }
128 }
129 };
130
131 if ( is_multisite() ) {
132 $wpstream_site_ids = get_sites(
133 array(
134 'fields' => 'ids',
135 'number' => 0,
136 )
137 );
138
139 foreach ( $wpstream_site_ids as $wpstream_site_id ) {
140 switch_to_blog( (int) $wpstream_site_id );
141 try {
142 $wpstream_cleanup_current_site();
143 } finally {
144 restore_current_blog();
145 }
146 }
147 } else {
148 $wpstream_cleanup_current_site();
149 }
150
151 // Streamify creates only generated cache data here, so the complete directory
152 // may be removed. Files are traversed child-first to support nested cache paths.
153 $wpstream_cache_dir = WP_CONTENT_DIR . '/uploads/wpstreamify_cache';
154 if ( is_dir( $wpstream_cache_dir ) ) {
155 $wpstream_cache_items = new RecursiveIteratorIterator(
156 new RecursiveDirectoryIterator( $wpstream_cache_dir, FilesystemIterator::SKIP_DOTS ),
157 RecursiveIteratorIterator::CHILD_FIRST
158 );
159
160 foreach ( $wpstream_cache_items as $wpstream_cache_item ) {
161 if ( $wpstream_cache_item->isDir() && ! $wpstream_cache_item->isLink() ) {
162 rmdir( $wpstream_cache_item->getPathname() );
163 } else {
164 unlink( $wpstream_cache_item->getPathname() );
165 }
166 }
167
168 rmdir( $wpstream_cache_dir );
169 }
170