delete( $dir, true ); } } /** * Builds the file name of a lightweight display copy. * * ASBPTP_Alt_Formats::alt_filename() と同じ規則。アンインストールでは * プラグイン本体を読み込まないので、規則だけをここに写している * (`foo-1200x630.jpg` → `foo-1200x630-jpg.webp`)。 * * @param string $name Original file name. * @param string $format 'webp' or 'avif'. * @return string Empty string when the name has no usable extension. */ function asbptp_uninstall_alt_filename( $name, $format ) { $name = (string) $name; $ext = strtolower( (string) pathinfo( $name, PATHINFO_EXTENSION ) ); if ( '' === $ext || ! preg_match( '/^[a-z0-9]+$/', $ext ) ) { return ''; } $stem = preg_replace( '/\.[^.]+$/', '', $name ); if ( '' === $stem ) { return ''; } return $stem . '-' . $ext . '.' . $format; } /** * Deletes plugin data for a specific site. * * ディレクトリ削除もここで行う。マルチサイトでは switch_to_blog 済みの状態で * 呼ばれるため、wp_upload_dir() は各サブサイト固有の uploads を返す。これにより * サブサイトの専用 uploads ディレクトリも取りこぼさず削除する(BUG-05)。 * * @param string $prefix The table prefix. * @param string $asbptp_option_name The option name to delete. * @param array $asbptp_meta_keys The meta keys to delete. * @param array $asbptp_cron_hooks The cron hooks to clear. */ function asbptp_uninstall_delete_data( $prefix, $asbptp_option_name, $asbptp_meta_keys, $asbptp_cron_hooks ) { global $wpdb; delete_option( $asbptp_option_name ); delete_option( 'asbptp_version' ); // 3.5.x までのライセンス関連オプション(4.0.0 以降は作られない。古い環境に残っていれば掃除) delete_option( 'asbptp_license_key' ); delete_option( 'asbptp_license_status' ); delete_option( 'asbptp_license_expires' ); delete_option( 'asbptp_license_last_check' ); delete_option( 'asbptp_license_signature' ); delete_option( 'asbptp_license_hmac_migrated' ); delete_option( 'asbptp_license_first_fail' ); delete_option( 'asbptp_license_activation_hash' ); delete_transient( 'asbptp_license_recheck_scheduled' ); // 形式の対応可否の実測結果 delete_transient( 'asbptp_format_support' ); // 宣伝サイドバー非表示トグル(一般タブで保存) delete_option( 'asbptp_family_promo_hidden' ); // 表示用の軽い複製(.webp / .avif)は添付の metadata に載らないので、 // WordPress は消してくれない。どこに置いたかを知っているのはこの meta だけ // なので、meta を消す前に実ファイルを片付ける。 // マルチサイトでは switch_to_blog() 済みで呼ばれるので、$wpdb->postmeta は // そのサブサイトの表を指す($prefix と同じ物)。テーブル名を自分で繋ぐより // 素直で、prepare() の検査も通る。 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- アンインストール時の一括掃除。キャッシュを経由する意味がない。 $asbptp_alt_rows = $wpdb->get_results( $wpdb->prepare( "SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE meta_key = %s", '_asbptp_alt_formats' ), ARRAY_A ); if ( $asbptp_alt_rows ) { foreach ( $asbptp_alt_rows as $asbptp_alt_row ) { $asbptp_alt_list = maybe_unserialize( $asbptp_alt_row['meta_value'] ); if ( ! is_array( $asbptp_alt_list ) ) { continue; } $asbptp_alt_file = get_attached_file( (int) $asbptp_alt_row['post_id'] ); if ( ! $asbptp_alt_file ) { continue; } $asbptp_alt_dir = trailingslashit( dirname( $asbptp_alt_file ) ); foreach ( $asbptp_alt_list as $asbptp_alt_format => $asbptp_alt_names ) { if ( ! in_array( $asbptp_alt_format, array( 'webp', 'avif' ), true ) || ! is_array( $asbptp_alt_names ) ) { continue; } foreach ( $asbptp_alt_names as $asbptp_alt_name ) { $asbptp_alt_base = asbptp_uninstall_alt_filename( wp_basename( (string) $asbptp_alt_name ), $asbptp_alt_format ); if ( '' === $asbptp_alt_base ) { continue; } $asbptp_alt_path = $asbptp_alt_dir . $asbptp_alt_base; if ( file_exists( $asbptp_alt_path ) ) { wp_delete_file( $asbptp_alt_path ); } } } } } // delete_post_meta_by_key() is the core way to drop one key from every // post; it also clears the post meta cache for the posts it touched. foreach ( $asbptp_meta_keys as $meta_key ) { delete_post_meta_by_key( $meta_key ); } foreach ( $asbptp_cron_hooks as $hook ) { wp_clear_scheduled_hook( $hook ); } // このサイト専用の uploads ディレクトリ(フォント / プレビュー)を削除 $upload_dir = wp_upload_dir(); if ( ! empty( $upload_dir['basedir'] ) ) { asbptp_recursive_rmdir( $upload_dir['basedir'] . '/asbptp-fonts' ); asbptp_recursive_rmdir( $upload_dir['basedir'] . '/asbptp-previews' ); } } if ( is_multisite() ) { $asbptp_blogs = get_sites( array( 'fields' => 'ids', 'number' => 0, ) ); if ( $asbptp_blogs ) { foreach ( $asbptp_blogs as $asbptp_blog_id ) { switch_to_blog( (int) $asbptp_blog_id ); asbptp_uninstall_delete_data( $wpdb->get_blog_prefix(), $asbptp_option_name, $asbptp_meta_keys, $asbptp_cron_hooks ); restore_current_blog(); } } } else { asbptp_uninstall_delete_data( $wpdb->prefix, $asbptp_option_name, $asbptp_meta_keys, $asbptp_cron_hooks ); } // 通知の非表示状態(usermeta はネットワーク共通テーブルなので一度だけ削除) delete_metadata( 'user', 0, 'asbptp_promo_dismissed', '', true );