Changeset 3487170
- Timestamp:
- 03/20/2026 11:54:32 AM (11 days ago)
- Location:
- tiny-backup
- Files:
-
- 24 added
- 2 deleted
- 28 edited
- 1 copied
-
assets/screenshot-1.png (modified) (1 prop) (previous)
-
assets/screenshot-2.png (modified) (1 prop) (previous)
-
tags/1.3.0 (copied) (copied from tiny-backup/trunk)
-
tags/1.3.0/.phpcs.xml (added)
-
tags/1.3.0/.prettierignore (added)
-
tags/1.3.0/.wordpress.org (added)
-
tags/1.3.0/.wordpress.org/screenshot-1.png (added)
-
tags/1.3.0/.wordpress.org/screenshot-2.png (added)
-
tags/1.3.0/assets (deleted)
-
tags/1.3.0/build (added)
-
tags/1.3.0/build/admin-rtl.css (added)
-
tags/1.3.0/build/admin.asset.php (added)
-
tags/1.3.0/build/admin.css (added)
-
tags/1.3.0/build/admin.js (added)
-
tags/1.3.0/includes/class-tnbu-admin-interface.php (modified) (10 diffs)
-
tags/1.3.0/includes/class-tnbu-ajax-handler.php (modified) (8 diffs)
-
tags/1.3.0/includes/class-tnbu-core.php (modified) (2 diffs)
-
tags/1.3.0/includes/class-tnbu-cron.php (added)
-
tags/1.3.0/includes/class-tnbu-database-backup.php (modified) (8 diffs)
-
tags/1.3.0/includes/class-tnbu-file-backup.php (modified) (7 diffs)
-
tags/1.3.0/includes/class-tnbu-utilities.php (modified) (1 diff)
-
tags/1.3.0/languages/tiny-backup-ja-tnbu-admin.json (modified) (1 diff)
-
tags/1.3.0/languages/tiny-backup-ja.mo (modified) (previous)
-
tags/1.3.0/languages/tiny-backup-ja.po (modified) (2 diffs)
-
tags/1.3.0/languages/tiny-backup.pot (modified) (1 diff)
-
tags/1.3.0/package-lock.json (added)
-
tags/1.3.0/readme.txt (modified) (7 diffs)
-
tags/1.3.0/tiny-backup.php (modified) (3 diffs)
-
tags/1.3.0/uninstall.php (modified) (1 diff)
-
trunk/.phpcs.xml (added)
-
trunk/.prettierignore (added)
-
trunk/.wordpress.org (added)
-
trunk/.wordpress.org/screenshot-1.png (added)
-
trunk/.wordpress.org/screenshot-2.png (added)
-
trunk/assets (deleted)
-
trunk/build (added)
-
trunk/build/admin-rtl.css (added)
-
trunk/build/admin.asset.php (added)
-
trunk/build/admin.css (added)
-
trunk/build/admin.js (added)
-
trunk/includes/class-tnbu-admin-interface.php (modified) (10 diffs)
-
trunk/includes/class-tnbu-ajax-handler.php (modified) (8 diffs)
-
trunk/includes/class-tnbu-core.php (modified) (2 diffs)
-
trunk/includes/class-tnbu-cron.php (added)
-
trunk/includes/class-tnbu-database-backup.php (modified) (8 diffs)
-
trunk/includes/class-tnbu-file-backup.php (modified) (7 diffs)
-
trunk/includes/class-tnbu-utilities.php (modified) (1 diff)
-
trunk/languages/tiny-backup-ja-tnbu-admin.json (modified) (1 diff)
-
trunk/languages/tiny-backup-ja.mo (modified) (previous)
-
trunk/languages/tiny-backup-ja.po (modified) (2 diffs)
-
trunk/languages/tiny-backup.pot (modified) (1 diff)
-
trunk/package-lock.json (added)
-
trunk/readme.txt (modified) (7 diffs)
-
trunk/tiny-backup.php (modified) (3 diffs)
-
trunk/uninstall.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
tiny-backup/assets/screenshot-1.png
-
Property
svn:mime-type
changed from
application/octet-streamtoimage/png
-
Property
svn:mime-type
changed from
-
tiny-backup/assets/screenshot-2.png
-
Property
svn:mime-type
changed from
application/octet-streamtoimage/png
-
Property
svn:mime-type
changed from
-
tiny-backup/tags/1.3.0/includes/class-tnbu-admin-interface.php
r3397691 r3487170 18 18 $screen = get_current_screen(); 19 19 if ( 'tools_page_tnbu' === $screen->id ) { 20 $asset_file = plugin_dir_path( __DIR__ ) . 'build/admin.asset.php'; 21 $asset = file_exists( $asset_file ) ? require $asset_file : array( 22 'dependencies' => array(), 23 'version' => TNBU_Utilities::get_version(), 24 ); 25 $deps = array_unique( array_merge( $asset['dependencies'], array( 'wp-i18n' ) ) ); 26 20 27 wp_enqueue_style( 21 28 'tnbu-style', 22 plugin_dir_url( __DIR__ ) . ' assets/css/admin.css',29 plugin_dir_url( __DIR__ ) . 'build/admin.css', 23 30 array(), 24 TNBU_Utilities::get_version()31 $asset['version'] 25 32 ); 26 33 wp_enqueue_script( 27 34 'tnbu-admin', 28 plugin_dir_url( __DIR__ ) . ' assets/js/admin.js',29 array( 'wp-i18n' ),30 TNBU_Utilities::get_version(),35 plugin_dir_url( __DIR__ ) . 'build/admin.js', 36 $deps, 37 $asset['version'], 31 38 true 32 39 ); … … 57 64 ); 58 65 wp_add_inline_script( 'tnbu-admin', $inline_script, 'before' ); 66 67 // 自動バックアップUI:スケジュール選択に応じて曜日/日付/時刻の表示切替 68 $auto_backup_script = <<<'JS' 69 document.addEventListener('DOMContentLoaded', function() { 70 document.querySelectorAll('.tnbu-auto-schedule').forEach(function(sel) { 71 sel.addEventListener('change', function() { 72 var row = this.closest('.tnbu-auto-backup-row'); 73 var val = this.value; 74 var dow = row.querySelector('.tnbu-auto-dow'); 75 var day = row.querySelector('.tnbu-auto-day'); 76 var time = row.querySelector('.tnbu-auto-time'); 77 dow.style.display = (val === 'weekly') ? '' : 'none'; 78 day.style.display = (val === 'monthly') ? '' : 'none'; 79 time.style.display = (val === '' || val === 'every_minute') ? 'none' : ''; 80 }); 81 }); 82 }); 83 JS; 84 wp_add_inline_script( 'tnbu-admin', $auto_backup_script, 'after' ); 59 85 } 60 86 } … … 100 126 register_setting( 'tnbu_settings_group', TNBU_Core::OPTION_KEY, array( __CLASS__, 'sanitize_settings' ) ); 101 127 // 単一セクション(見出しなし) 102 add_settings_section( 'tnbu_section_settings', __( 'Settings', 'tiny-backup' ), '__return_false', 'tnbu' ); 103 104 // 最上部: 横並びチェックボックス(DB/ファイル) 105 add_settings_field( 'backup_toggles', __( 'Backup targets', 'tiny-backup' ), array( __CLASS__, 'field_backup_toggles' ), 'tnbu', 'tnbu_section_settings' ); 106 107 // ファイル設定: ファイル名テンプレート(固定のため表示なし) 108 add_settings_field( 109 'files_selection', 110 __( 'Select backup items', 'tiny-backup' ) . '<br>' . __( 'only under wp-content', 'tiny-backup' ), 111 array( __CLASS__, 'field_files_selection' ), 112 'tnbu', 113 'tnbu_section_settings' 114 ); 128 add_settings_section( 'tnbu_section_settings', '', '__return_false', 'tnbu' ); 129 130 // ファイルバックアップ対象選択セクション 131 add_settings_field( 'files_selection', '', array( __CLASS__, 'field_files_selection' ), 'tnbu', 'tnbu_section_files' ); 132 133 // 自動バックアップセクション 134 add_settings_section( 'tnbu_section_auto', __( 'Auto Backup', 'tiny-backup' ), array( __CLASS__, 'section_auto_description' ), 'tnbu' ); 135 add_settings_field( 'auto_backup_db', __( 'Database', 'tiny-backup' ), array( __CLASS__, 'field_auto_backup_db' ), 'tnbu', 'tnbu_section_auto' ); 136 add_settings_field( 'auto_backup_files', _x( 'Files', 'auto backup setting', 'tiny-backup' ), array( __CLASS__, 'field_auto_backup_files' ), 'tnbu', 'tnbu_section_auto' ); 137 add_settings_field( 'auto_backup_email', __( 'Email notification', 'tiny-backup' ), array( __CLASS__, 'field_auto_backup_email' ), 'tnbu', 'tnbu_section_auto' ); 115 138 116 139 // 共通設定: 保存先ディレクトリ(固定化のためUI非表示) 117 }118 119 /**120 * バックアップ対象のトグルボタンを表示121 * データベースとファイルのバックアップ有効/無効を切り替え122 */123 public static function field_backup_toggles() {124 $opts = TNBU_Core::get_options();125 $is_db_backup_enabled = ! empty( $opts['backup_db'] );126 $is_files_backup_enabled = ! empty( $opts['backup_files'] );127 ?>128 <div class="tnbu-backup-toggles">129 <label>130 <input type="checkbox" name="<?php echo esc_attr( TNBU_Core::OPTION_KEY ); ?>[backup_db]" value="1" <?php checked( $is_db_backup_enabled, true ); ?> /> <?php echo esc_html( __( 'Backup database', 'tiny-backup' ) ); ?>131 </label>132 <label>133 <input type="checkbox" name="<?php echo esc_attr( TNBU_Core::OPTION_KEY ); ?>[backup_files]" value="1" <?php checked( $is_files_backup_enabled, true ); ?> /> <?php echo esc_html( _x( 'Backup files', 'checkbox label', 'tiny-backup' ) ); ?>134 </label>135 </div>136 <?php137 140 } 138 141 … … 149 152 $rel = ltrim( $rel, '/' ); 150 153 $output['target_dir'] = ( '' !== $rel ) ? $rel : TNBU_Core::DEFAULT_DIR_SUFFIX; 151 // do not store files filename template152 // backup switches (checkboxes)153 $output['backup_db'] = ! empty( $input['backup_db'] ) ? 1 : 0;154 $output['backup_files'] = ! empty( $input['backup_files'] ) ? 1 : 0;155 154 // save selected items from settings form (if present) 156 155 $sel = isset( $input['selected_items'] ) && is_array( $input['selected_items'] ) ? array_map( 'sanitize_text_field', $input['selected_items'] ) : array(); … … 170 169 ); 171 170 $output['selected_items'] = $sel; 171 172 // 自動バックアップ設定のサニタイズ 173 $valid_schedules = array( '', 'daily', 'weekly', 'monthly' ); 174 if ( defined( 'TNBU_CRON_DEBUG' ) && TNBU_CRON_DEBUG ) { 175 $valid_schedules[] = 'every_minute'; 176 } 177 foreach ( array( 'auto_backup_db', 'auto_backup_files' ) as $prefix ) { 178 $sched = isset( $input[ $prefix . '_schedule' ] ) ? sanitize_text_field( $input[ $prefix . '_schedule' ] ) : ''; 179 $output[ $prefix . '_schedule' ] = in_array( $sched, $valid_schedules, true ) ? $sched : ''; 180 181 $time = isset( $input[ $prefix . '_time' ] ) ? sanitize_text_field( $input[ $prefix . '_time' ] ) : '03:00'; 182 if ( preg_match( '/^(\d{1,2}):(\d{2})$/', $time, $m ) ) { 183 $output[ $prefix . '_time' ] = sprintf( '%02d:%s', max( 0, min( 23, (int) $m[1] ) ), ( (int) $m[2] >= 30 ? '30' : '00' ) ); 184 } else { 185 $output[ $prefix . '_time' ] = '03:00'; 186 } 187 188 $dow = isset( $input[ $prefix . '_day_of_week' ] ) ? (int) $input[ $prefix . '_day_of_week' ] : 0; 189 $output[ $prefix . '_day_of_week' ] = (string) max( 0, min( 6, $dow ) ); 190 191 $day = isset( $input[ $prefix . '_day' ] ) ? (int) $input[ $prefix . '_day' ] : 1; 192 $output[ $prefix . '_day' ] = (string) max( 1, min( 28, $day ) ); 193 } 194 195 $max_gen = isset( $input['auto_backup_db_max_generations'] ) ? (int) $input['auto_backup_db_max_generations'] : TNBU_Core::DEFAULT_AUTO_MAX_GENERATIONS; 196 $output['auto_backup_db_max_generations'] = max( 1, min( 10, $max_gen ) ); 197 198 $max_gen = isset( $input['auto_backup_files_max_generations'] ) ? (int) $input['auto_backup_files_max_generations'] : TNBU_Core::DEFAULT_AUTO_MAX_GENERATIONS; 199 $output['auto_backup_files_max_generations'] = max( 1, min( 10, $max_gen ) ); 200 201 $output['auto_backup_email_success'] = ! empty( $input['auto_backup_email_success'] ); 202 $output['auto_backup_email_failure'] = ! empty( $input['auto_backup_email_failure'] ); 203 172 204 return $output; 173 205 } … … 175 207 /** 176 208 * ファイルバックアップ対象選択UIを表示 177 * wp-content配下のファイル・フォルダをツリー形式で選択可能178 209 */ 179 210 public static function field_files_selection() { … … 184 215 </div> 185 216 </div> 217 218 <hr class="tnbu-divider" /> 219 220 <?php 221 } 222 223 /** 224 * 自動バックアップセクションの説明文 225 */ 226 public static function section_auto_description() { 227 echo '<p class="description">' . esc_html__( 'Automatic backups use the same targets as manual backups. Actual execution timing may vary depending on site traffic.', 'tiny-backup' ) . '</p>'; 228 } 229 230 /** 231 * スケジュール選択肢を返す 232 * 233 * @return array 234 */ 235 private static function get_schedule_options() { 236 $options = array( 237 '' => __( 'Disabled', 'tiny-backup' ), 238 'daily' => __( 'Daily', 'tiny-backup' ), 239 'weekly' => __( 'Weekly', 'tiny-backup' ), 240 'monthly' => __( 'Monthly', 'tiny-backup' ), 241 ); 242 if ( defined( 'TNBU_CRON_DEBUG' ) && TNBU_CRON_DEBUG ) { 243 $options['every_minute'] = __( 'Every Minute (debug)', 'tiny-backup' ); 244 } 245 return $options; 246 } 247 248 /** 249 * 時刻選択肢を返す(0〜23時) 250 * 251 * @return array 252 */ 253 private static function get_time_options() { 254 $times = array(); 255 for ( $h = 0; $h < 24; $h++ ) { 256 foreach ( array( '00', '30' ) as $m ) { 257 $key = sprintf( '%02d:%s', $h, $m ); 258 $times[ $key ] = $key; 259 } 260 } 261 return $times; 262 } 263 264 /** 265 * 曜日選択肢を返す 266 * 267 * @return array 268 */ 269 private static function get_dow_options() { 270 return array( 271 '0' => __( 'Sunday', 'tiny-backup' ), 272 '1' => __( 'Monday', 'tiny-backup' ), 273 '2' => __( 'Tuesday', 'tiny-backup' ), 274 '3' => __( 'Wednesday', 'tiny-backup' ), 275 '4' => __( 'Thursday', 'tiny-backup' ), 276 '5' => __( 'Friday', 'tiny-backup' ), 277 '6' => __( 'Saturday', 'tiny-backup' ), 278 ); 279 } 280 281 /** 282 * 自動バックアップ行(スケジュール+時刻+曜日/日付)をレンダリング 283 * 284 * @param string $prefix 設定キーのプレフィックス('auto_backup_db' or 'auto_backup_files') 285 */ 286 private static function render_auto_backup_row( $prefix ) { 287 $opts = TNBU_Core::get_options(); 288 $opt_key = TNBU_Core::OPTION_KEY; 289 $schedule = $opts[ $prefix . '_schedule' ] ?? ''; 290 $time = $opts[ $prefix . '_time' ] ?? '03'; 291 $dow = $opts[ $prefix . '_day_of_week' ] ?? '0'; 292 $day = $opts[ $prefix . '_day' ] ?? '1'; 293 ?> 294 <div class="tnbu-auto-backup-row" data-prefix="<?php echo esc_attr( $prefix ); ?>"> 295 <select name="<?php echo esc_attr( $opt_key ); ?>[<?php echo esc_attr( $prefix . '_schedule' ); ?>]" class="tnbu-auto-schedule"> 296 <?php foreach ( self::get_schedule_options() as $val => $label ) : ?> 297 <option value="<?php echo esc_attr( $val ); ?>" <?php selected( $schedule, $val ); ?>><?php echo esc_html( $label ); ?></option> 298 <?php endforeach; ?> 299 </select> 300 301 <span class="tnbu-auto-dow" <?php echo 'weekly' !== $schedule ? 'style="display:none;"' : ''; ?>> 302 <select name="<?php echo esc_attr( $opt_key ); ?>[<?php echo esc_attr( $prefix . '_day_of_week' ); ?>]"> 303 <?php foreach ( self::get_dow_options() as $val => $label ) : ?> 304 <option value="<?php echo esc_attr( $val ); ?>" <?php selected( $dow, $val ); ?>><?php echo esc_html( $label ); ?></option> 305 <?php endforeach; ?> 306 </select> 307 </span> 308 309 <span class="tnbu-auto-day" <?php echo 'monthly' !== $schedule ? 'style="display:none;"' : ''; ?>> 310 <select name="<?php echo esc_attr( $opt_key ); ?>[<?php echo esc_attr( $prefix . '_day' ); ?>]"> 311 <?php for ( $d = 1; $d <= 28; $d++ ) : ?> 312 <option value="<?php echo esc_attr( $d ); ?>" <?php selected( $day, (string) $d ); ?>><?php echo esc_html( $d ); ?></option> 313 <?php endfor; ?> 314 </select> 315 <?php echo esc_html__( 'day', 'tiny-backup' ); ?> 316 </span> 317 318 <span class="tnbu-auto-time" <?php echo ( '' === $schedule || 'every_minute' === $schedule ) ? 'style="display:none;"' : ''; ?>> 319 <select name="<?php echo esc_attr( $opt_key ); ?>[<?php echo esc_attr( $prefix . '_time' ); ?>]"> 320 <?php foreach ( self::get_time_options() as $val => $label ) : ?> 321 <option value="<?php echo esc_attr( $val ); ?>" <?php selected( $time, $val ); ?>><?php echo esc_html( $label ); ?></option> 322 <?php endforeach; ?> 323 </select> 324 </span> 325 326 <?php 327 $max_key = $prefix . '_max_generations'; 328 $max_val = $opts[ $max_key ] ?? TNBU_Core::DEFAULT_AUTO_MAX_GENERATIONS; 329 ?> 330 <span class="tnbu-auto-max-gen" <?php echo '' === $schedule ? 'style="display:none;"' : 'style="margin-left:2rem;"'; ?>> 331 <?php echo esc_html__( 'Max generations', 'tiny-backup' ); ?>: 332 <select name="<?php echo esc_attr( $opt_key ); ?>[<?php echo esc_attr( $max_key ); ?>]"> 333 <?php for ( $i = 1; $i <= 10; $i++ ) : ?> 334 <option value="<?php echo esc_attr( $i ); ?>" <?php selected( (int) $max_val, $i ); ?>><?php echo esc_html( $i ); ?></option> 335 <?php endfor; ?> 336 </select> 337 </span> 338 </div> 339 <?php 340 } 341 342 /** 343 * DB自動バックアップ設定フィールド 344 */ 345 public static function field_auto_backup_db() { 346 self::render_auto_backup_row( 'auto_backup_db' ); 347 } 348 349 /** 350 * ファイル自動バックアップ設定フィールド 351 */ 352 public static function field_auto_backup_files() { 353 self::render_auto_backup_row( 'auto_backup_files' ); 354 } 355 356 /** 357 * DB保持世代数設定フィールド 358 */ 359 public static function field_auto_backup_db_max_generations() { 360 $opts = TNBU_Core::get_options(); 361 $max = $opts['auto_backup_db_max_generations'] ?? TNBU_Core::DEFAULT_AUTO_MAX_GENERATIONS; 362 ?> 363 <select name="<?php echo esc_attr( TNBU_Core::OPTION_KEY ); ?>[auto_backup_db_max_generations]"> 364 <?php for ( $i = 1; $i <= 10; $i++ ) : ?> 365 <option value="<?php echo esc_attr( $i ); ?>" <?php selected( (int) $max, $i ); ?>><?php echo esc_html( $i ); ?></option> 366 <?php endfor; ?> 367 </select> 368 <?php 369 } 370 371 /** 372 * ファイル保持世代数設定フィールド 373 */ 374 public static function field_auto_backup_files_max_generations() { 375 $opts = TNBU_Core::get_options(); 376 $max = $opts['auto_backup_files_max_generations'] ?? TNBU_Core::DEFAULT_AUTO_MAX_GENERATIONS; 377 ?> 378 <select name="<?php echo esc_attr( TNBU_Core::OPTION_KEY ); ?>[auto_backup_files_max_generations]"> 379 <?php for ( $i = 1; $i <= 10; $i++ ) : ?> 380 <option value="<?php echo esc_attr( $i ); ?>" <?php selected( (int) $max, $i ); ?>><?php echo esc_html( $i ); ?></option> 381 <?php endfor; ?> 382 </select> 383 <?php 384 } 385 386 /** 387 * メール通知設定フィールド 388 */ 389 public static function field_auto_backup_email() { 390 $opts = TNBU_Core::get_options(); 391 $key = esc_attr( TNBU_Core::OPTION_KEY ); 392 $email = get_option( 'admin_email' ); 393 $success = ! empty( $opts['auto_backup_email_success'] ); 394 $failure = ! empty( $opts['auto_backup_email_failure'] ); 395 ?> 396 <p class="description" style="margin-bottom: 8px;"> 397 <?php echo esc_html( sprintf( 398 /* translators: %s: admin email address */ 399 __( 'Send notification to %s', 'tiny-backup' ), 400 $email 401 ) ); ?> 402 </p> 403 <label style="margin-right: 16px;"> 404 <input type="hidden" name="<?php echo $key; ?>[auto_backup_email_success]" value="0" /> 405 <input type="checkbox" name="<?php echo $key; ?>[auto_backup_email_success]" value="1" <?php checked( $success ); ?> /> 406 <?php echo esc_html__( 'On success', 'tiny-backup' ); ?> 407 </label> 408 <label> 409 <input type="hidden" name="<?php echo $key; ?>[auto_backup_email_failure]" value="0" /> 410 <input type="checkbox" name="<?php echo $key; ?>[auto_backup_email_failure]" value="1" <?php checked( $failure ); ?> /> 411 <?php echo esc_html__( 'On failure', 'tiny-backup' ); ?> 412 </label> 186 413 <?php 187 414 } … … 222 449 223 450 <form id="tnbu-settings-form" class="tnbu-settings-form" method="post" action="options.php"> 451 <h3><?php echo esc_html( __( 'Choose what to backup from your uploads folder.', 'tiny-backup' ) ); ?></h3> 452 <?php self::field_files_selection(); ?> 453 224 454 <?php settings_fields( 'tnbu_settings_group' ); ?> 225 455 <?php do_settings_sections( 'tnbu' ); ?> 226 <?php /* ファイル選択はセクションフィールド側で描画 */ ?>227 456 <?php submit_button( __( 'Save Settings', 'tiny-backup' ) ); ?> 228 457 </form> 458 229 459 <form id="tnbu-reset-form" class="tnbu-reset-form" method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>"> 230 460 <input type="hidden" name="action" value="tnbu_reset_settings" /> … … 236 466 <hr class="tnbu-divider" /> 237 467 238 <h2><?php echo esc_html( __( 'Backup', 'tiny-backup' ) ); ?></h2> 239 <p> 240 <button type="button" class="button button-primary" id="tnbu-backup-button"><?php echo esc_html( __( 'Run backup now', 'tiny-backup' ) ); ?></button> 468 <h2><?php echo esc_html( __( 'Run backup now', 'tiny-backup' ) ); ?></h2> 469 <p class="tnbu-backup-buttons"> 470 <button type="button" class="button button-primary tnbu-backup-trigger" data-backup-type="db"><?php echo esc_html( __( 'Database backup', 'tiny-backup' ) ); ?></button> 471 <button type="button" class="button button-primary tnbu-backup-trigger" data-backup-type="files"><?php echo esc_html( __( 'Files backup', 'tiny-backup' ) ); ?></button> 241 472 </p> 242 473 <?php … … 251 482 </div> 252 483 253 484 <hr class="tnbu-divider" /> 254 485 255 486 <!-- バックアップファイル一覧 --> 256 487 <div class="tnbu-backup-list"> 257 <h 3><?php echo esc_html( _x( 'Backup files', 'section title', 'tiny-backup' ) ); ?></h3>488 <h2><?php echo esc_html( _x( 'Backup files', 'section title', 'tiny-backup' ) ); ?></h2> 258 489 <?php self::render_backup_list(); ?> 259 490 </div> -
tiny-backup/tags/1.3.0/includes/class-tnbu-ajax-handler.php
r3397691 r3487170 24 24 } 25 25 26 // バックアップ実行前に設定を保存(変更された設定があれば保存する) 27 if ( isset( $_POST['tnbu_backup_db'] ) || isset( $_POST['tnbu_backup_files'] ) ) { 28 $current_opts = TNBU_Core::get_options(); 29 $updated_opts = $current_opts; 30 31 // チェックボックスの状態を更新 32 if ( isset( $_POST['tnbu_backup_db'] ) ) { 33 $updated_opts['backup_db'] = ( sanitize_text_field( wp_unslash( $_POST['tnbu_backup_db'] ) ) === '1' ) ? 1 : 0; 34 } 35 if ( isset( $_POST['tnbu_backup_files'] ) ) { 36 $updated_opts['backup_files'] = ( sanitize_text_field( wp_unslash( $_POST['tnbu_backup_files'] ) ) === '1' ) ? 1 : 0; 37 } 38 39 // 選択されたアイテムを更新(常に更新する、空でも) 40 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized in array_map below 41 $selected = isset( $_POST['tnbu_selected_items'] ) ? (array) wp_unslash( $_POST['tnbu_selected_items'] ) : array(); 42 $selected = array_map( 43 function ( $p ) { 44 return ltrim( (string) sanitize_text_field( $p ), '/' ); 45 }, 46 $selected 47 ); 48 $selected = array_values( 49 array_filter( 50 array_unique( $selected ), 51 function ( $p ) { 52 return '' !== $p && false === strpos( $p, '..' ) && false === strpos( $p, "\0" ); 53 } 54 ) 55 ); 56 // 空の配列でも保存する(選択を解除した場合のため) 57 $updated_opts['selected_items'] = $selected; 58 59 // 設定を保存 60 update_option( TNBU_Core::OPTION_KEY, $updated_opts ); 61 62 /* translators: 1: DB backup enabled (0/1), 2: Files backup enabled (0/1) */ 63 TNBU_Progress_Manager::set_progress( sprintf( __( 'Settings saved: DB=%1$s, Files=%2$s', 'tiny-backup' ), $updated_opts['backup_db'], $updated_opts['backup_files'] ), false, null ); 26 // バックアップ種別を取得('db' or 'files') 27 $backup_type = isset( $_POST['backup_type'] ) ? sanitize_text_field( wp_unslash( $_POST['backup_type'] ) ) : ''; 28 if ( ! in_array( $backup_type, array( 'db', 'files' ), true ) ) { 29 wp_send_json_error( array( 'message' => 'invalid_backup_type' ), 400 ); 64 30 } 65 31 66 32 TNBU_Progress_Manager::set_progress( __( 'Backup started', 'tiny-backup' ), false, null ); 67 // 設定に応じてDB/ファイルのバックアップを実行(キャッシュを強制リフレッシュ) 68 $opts = TNBU_Core::get_options( true ); 69 $last_result_path = ''; 70 $db_result_path = ''; 71 $files_result_path = ''; 72 $error = null; 73 $total_steps = 0; 74 $current_step = 0; 75 76 // 実行するバックアップの種類をカウント 77 if ( ! empty( $opts['backup_db'] ) ) { 78 ++$total_steps; 79 } 80 if ( ! empty( $opts['backup_files'] ) ) { 81 ++$total_steps; 82 } 83 84 /* translators: 1: whether DB backup is enabled (0/1), 2: whether Files backup is enabled (0/1) */ 85 TNBU_Progress_Manager::set_progress( sprintf( __( 'Checking backup settings: DB=%1$s, Files=%2$s', 'tiny-backup' ), $opts['backup_db'], $opts['backup_files'] ), false, null ); 86 87 if ( ! empty( $opts['backup_db'] ) ) { 88 ++$current_step; 33 34 $result_path = ''; 35 $error = null; 36 37 if ( 'db' === $backup_type ) { 89 38 TNBU_Progress_Manager::set_progress( __( 'Starting database backup', 'tiny-backup' ), false, null ); 90 39 $res = TNBU_Database_Backup::perform_backup(); … … 94 43 TNBU_Progress_Manager::set_progress( sprintf( __( 'Database backup error: %s', 'tiny-backup' ), $res->get_error_message() ), false, null ); 95 44 } else { 96 $db_result_path = $res; 97 $last_result_path = $res; 45 $result_path = $res; 98 46 TNBU_Progress_Manager::set_progress( __( 'Database backup completed', 'tiny-backup' ), false, null ); 99 47 } 100 48 } 101 49 102 if ( ! empty( $opts['backup_files'] ) ) { 103 ++$current_step; 50 if ( 'files' === $backup_type ) { 104 51 TNBU_Progress_Manager::set_progress( __( 'Starting files backup', 'tiny-backup' ), false, null ); 105 52 106 // ユーザーが選択した項目があればそれを優先、なければ自動スキャン 107 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized in array_map below 108 $selected = isset( $_POST['tnbu_selected_items'] ) ? (array) wp_unslash( $_POST['tnbu_selected_items'] ) : array(); 109 $selected = array_map( 110 function ( $p ) { 111 return ltrim( (string) sanitize_text_field( $p ), '/' ); 112 }, 113 $selected 114 ); 115 $selected = array_values( 116 array_filter( 117 array_unique( $selected ), 118 function ( $p ) { 119 return '' !== $p && false === strpos( $p, '..' ) && false === strpos( $p, "\0" ); 120 } 121 ) 122 ); 123 if ( empty( $selected ) && ! empty( $opts['selected_items'] ) && is_array( $opts['selected_items'] ) ) { 124 $selected = array_values( 125 array_filter( 126 array_map( 127 function ( $p ) { 128 return ltrim( (string) $p, '/' ); 129 }, 130 $opts['selected_items'] 53 // POSTから選択アイテムを取得、なければ保存済み設定から取得 54 $selected = self::sanitize_selected_items_from_post(); 55 if ( empty( $selected ) ) { 56 $opts = TNBU_Core::get_options( true ); 57 if ( ! empty( $opts['selected_items'] ) && is_array( $opts['selected_items'] ) ) { 58 $selected = array_values( 59 array_filter( 60 array_map( 61 function ( $p ) { 62 return ltrim( (string) $p, '/' ); 63 }, 64 $opts['selected_items'] 65 ) 131 66 ) 132 ) 133 ); 134 } 135 136 /* translators: %d: number of selected items */ 137 TNBU_Progress_Manager::set_progress( sprintf( __( 'Selected files check: %d items', 'tiny-backup' ), count( $selected ) ), false, null ); 67 ); 68 } 69 } 138 70 139 71 if ( empty( $selected ) ) { 140 $fres = new WP_Error( 'tnbu_files_none', __( 'No file targets selected for backup', 'tiny-backup' ) ); 72 $error = new WP_Error( 'tnbu_files_none', __( 'No file targets selected for backup', 'tiny-backup' ) ); 73 TNBU_Progress_Manager::set_progress( $error->get_error_message(), false, null ); 141 74 } else { 142 75 $fres = TNBU_File_Backup::perform_files_backup_selected( $selected ); 143 } 144 if ( is_wp_error( $fres ) ) { 145 $error = $error ? $error : $fres; 146 /* translators: %s: error message */ 147 TNBU_Progress_Manager::set_progress( sprintf( __( 'Files backup error: %s', 'tiny-backup' ), $fres->get_error_message() ), false, null ); 148 } else { 149 $files_result_path = $fres; 150 $last_result_path = $fres; 151 TNBU_Progress_Manager::set_progress( __( 'Files backup completed: ', 'tiny-backup' ), false, null ); 152 } 153 } 154 $result = $error ? $error : ( $last_result_path ? $last_result_path : '' ); 155 if ( is_wp_error( $result ) ) { 76 if ( is_wp_error( $fres ) ) { 77 $error = $fres; 78 /* translators: %s: error message */ 79 TNBU_Progress_Manager::set_progress( sprintf( __( 'Files backup error: %s', 'tiny-backup' ), $fres->get_error_message() ), false, null ); 80 } else { 81 $result_path = $fres; 82 TNBU_Progress_Manager::set_progress( __( 'Files backup completed', 'tiny-backup' ), false, null ); 83 } 84 } 85 } 86 87 if ( $error ) { 156 88 set_transient( 157 89 'tnbu_flash_' . get_current_user_id(), … … 159 91 'type' => 'error', 160 92 /* translators: %s: error message */ 161 'text' => sprintf( __( 'Backup failed: %s', 'tiny-backup' ), $ result->get_error_message() ),93 'text' => sprintf( __( 'Backup failed: %s', 'tiny-backup' ), $error->get_error_message() ), 162 94 ), 163 95 60 164 96 ); 165 97 /* translators: %s: error message */ 166 TNBU_Progress_Manager::set_progress( sprintf( __( 'Error: %s', 'tiny-backup' ), $result->get_error_message() ), true, null ); 167 wp_send_json_error( array( 'message' => $result->get_error_message() ) ); 168 } 169 170 // バックアップ完了メッセージの作成 171 $backup_files = array(); 172 if ( $db_result_path ) { 173 $backup_files[] = basename( $db_result_path ); 174 } 175 if ( $files_result_path ) { 176 $backup_files[] = basename( $files_result_path ); 177 } 178 179 $files_text = implode( ', ', $backup_files ); 180 /* translators: %s: backup file names */ 98 TNBU_Progress_Manager::set_progress( sprintf( __( 'Error: %s', 'tiny-backup' ), $error->get_error_message() ), true, null ); 99 wp_send_json_error( array( 'message' => $error->get_error_message() ) ); 100 } 101 102 /* translators: %s: backup file name */ 181 103 set_transient( 182 104 'tnbu_flash_' . get_current_user_id(), 183 105 array( 184 106 'type' => 'success', 185 /* translators: %s: backup file name s*/186 'text' => sprintf( __( 'Backup completed: %s', 'tiny-backup' ), $files_text),107 /* translators: %s: backup file name */ 108 'text' => sprintf( __( 'Backup completed: %s', 'tiny-backup' ), basename( $result_path ) ), 187 109 ), 188 110 60 189 111 ); 190 112 TNBU_Progress_Manager::set_progress( __( 'Completed', 'tiny-backup' ), true, null ); 191 wp_send_json_success( array( 'path' => $result ) );113 wp_send_json_success( array( 'path' => $result_path ) ); 192 114 } 193 115 … … 214 136 wp_send_json_error( array( 'message' => 'bad_nonce' ), 403 ); 215 137 } 216 $rel = isset( $_POST['path'] ) ? sanitize_text_field( wp_unslash( $_POST['path'] ) ) : ''; 217 $rel = ltrim( $rel, '/' ); 218 $base = trailingslashit( WP_CONTENT_DIR ); 219 $target = $base . $rel; 138 $rel = isset( $_POST['path'] ) ? sanitize_text_field( wp_unslash( $_POST['path'] ) ) : ''; 139 $rel = ltrim( $rel, '/' ); 140 $base = trailingslashit( WP_CONTENT_DIR . '/uploads' ); 141 142 // 1階層のみ表示。pathが空以外の場合は許可しない 143 if ( '' !== $rel ) { 144 wp_send_json_error( array( 'message' => 'depth_limit' ), 400 ); 145 } 146 147 $target = $base; 220 148 $real_base = realpath( $base ); 221 $real_target = realpath( $target ) ? $target : $target; // 未存在でも操作しないのでOK149 $real_target = realpath( $target ) ? $target : $target; 222 150 if ( $real_base && $real_target && 0 !== strpos( wp_normalize_path( $real_target ), wp_normalize_path( $real_base ) ) ) { 223 151 wp_send_json_error( array( 'message' => 'invalid_path' ), 400 ); 224 }225 if ( ! is_dir( $target ) ) {226 $target = $base; // ルート227 152 } 228 153 $items = array(); … … 246 171 $full = $target . DIRECTORY_SEPARATOR . $entry; 247 172 $type = is_dir( $full ) ? 'dir' : 'file'; 248 $relp = ltrim( trim( $rel . '/' . $entry, '/' ) );173 $relp = 'uploads/' . $entry; 249 174 $items[] = array( 250 175 'name' => $entry, … … 353 278 header( 'Pragma: no-cache' ); 354 279 355 // WordPress Filesystem APIを使用してファイル送信 356 if ( ! function_exists( 'WP_Filesystem' ) ) { 357 require_once ABSPATH . 'wp-admin/includes/file.php'; 358 } 359 WP_Filesystem(); 360 global $wp_filesystem; 361 362 if ( ! $wp_filesystem->exists( $file_path ) ) { 363 wp_die( esc_html__( 'File not found.', 'tiny-backup' ) ); 364 } 365 366 $file_content = $wp_filesystem->get_contents( $file_path ); 367 if ( false === $file_content ) { 368 wp_die( esc_html__( 'File read error.', 'tiny-backup' ) ); 369 } 370 371 // チャンクごとに出力 372 $chunk_size = 1024 * 1024; // 1MB 373 $file_length = strlen( $file_content ); 374 for ( $i = 0; $i < $file_length; $i += $chunk_size ) { 375 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Binary file download, escaping would corrupt the data 376 echo substr( $file_content, $i, $chunk_size ); 377 flush(); 378 } 280 // ストリーミングでファイル送信(メモリ節約) 281 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_readfile -- Binary file streaming for download, WP_Filesystem::get_contents() would load entire file into memory 282 readfile( $file_path ); 379 283 exit; 380 284 } 381 285 286 287 /** 288 * POSTデータから選択アイテムをサニタイズして取得する 289 * 290 * @return array サニタイズ済みの選択アイテム配列 291 */ 292 private static function sanitize_selected_items_from_post() { 293 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized in array_map below 294 $selected = isset( $_POST['tnbu_selected_items'] ) ? (array) wp_unslash( $_POST['tnbu_selected_items'] ) : array(); 295 $selected = array_map( 296 function ( $p ) { 297 return ltrim( (string) sanitize_text_field( $p ), '/' ); 298 }, 299 $selected 300 ); 301 return array_values( 302 array_filter( 303 array_unique( $selected ), 304 function ( $p ) { 305 return '' !== $p && false === strpos( $p, '..' ) && false === strpos( $p, "\0" ); 306 } 307 ) 308 ); 309 } 382 310 383 311 /** … … 393 321 $files = isset( $_POST['files'] ) && is_array( $_POST['files'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['files'] ) ) : array(); 394 322 $base = trailingslashit( TNBU_Core::get_backup_dir() ); 395 $deleted = 0;396 323 foreach ( $files as $filename ) { 397 324 if ( ! TNBU_Utilities::validate_backup_filename( $filename ) ) { … … 399 326 } 400 327 $path = $base . $filename; 401 if ( is_file( $path ) && strpos( realpath( $path ), realpath( $base ) ) === 0 && wp_delete_file( $path )) {402 ++$deleted;328 if ( is_file( $path ) && strpos( realpath( $path ), realpath( $base ) ) === 0 ) { 329 wp_delete_file( $path ); 403 330 } 404 331 } -
tiny-backup/tags/1.3.0/includes/class-tnbu-core.php
r3397691 r3487170 72 72 * @return array デフォルト設定の配列 73 73 */ 74 // 自動バックアップのファイル名テンプレート(-auto 付き) 75 const DEFAULT_AUTO_DB_FILENAME_TEMPLATE = '{db}-{date}-auto-db'; 76 const DEFAULT_AUTO_FILES_FILENAME_TEMPLATE = '{db}-{date}-auto-files'; 77 78 // 自動バックアップの保持世代数デフォルト 79 const DEFAULT_AUTO_MAX_GENERATIONS = 3; 80 74 81 public static function defaults() { 75 82 return array( 76 83 // filename_template is fixed by code to DEFAULT_DB_FILENAME_TEMPLATE 77 84 'target_dir' => self::DEFAULT_DIR_SUFFIX, 78 'backup_db' => 1,79 'backup_files' => 1,80 85 // files filename template is fixed by code to DEFAULT_FILES_FILENAME_TEMPLATE 81 86 'selected_items' => array( 'uploads' ), 87 88 // 自動バックアップ設定 89 'auto_backup_db_schedule' => '', // '' | 'daily' | 'weekly' | 'monthly' 90 'auto_backup_db_time' => '03:00', // '00:00'〜'23:30' 91 'auto_backup_db_day_of_week' => '0', // 0(日)〜6(土) 92 'auto_backup_db_day' => '1', // 1〜28 93 'auto_backup_files_schedule' => '', 94 'auto_backup_files_time' => '03:00', 95 'auto_backup_files_day_of_week' => '0', 96 'auto_backup_files_day' => '1', 97 'auto_backup_db_max_generations' => self::DEFAULT_AUTO_MAX_GENERATIONS, 98 'auto_backup_files_max_generations' => self::DEFAULT_AUTO_MAX_GENERATIONS, 99 'auto_backup_email_success' => false, 100 'auto_backup_email_failure' => false, 82 101 ); 83 102 } … … 116 135 } 117 136 118 /**119 * 設定オプションのキャッシュをクリアする120 * 設定を更新した後に呼び出すことで、次回の get_options() で最新の値を取得できる121 *122 * @return void123 */124 public static function clear_options_cache() {125 // 次回の get_options() で強制的に再読み込みさせるため、引数で制御126 // このメソッドは互換性のために残しているが、get_options(true) を推奨127 }128 137 } -
tiny-backup/tags/1.3.0/includes/class-tnbu-database-backup.php
r3397691 r3487170 18 18 * @return string|WP_Error 成功時はファイルパス、失敗時はWP_Error 19 19 */ 20 public static function perform_backup() { 20 /** 21 * データベースのバックアップを実行する 22 * 23 * @param string|null $filename_template ファイル名テンプレート(null の場合はデフォルト) 24 * @return string|WP_Error 成功時はファイルパス、失敗時はWP_Error 25 */ 26 public static function perform_backup( $filename_template = null ) { 21 27 global $wpdb; 22 28 $abs_dir = TNBU_Core::get_backup_dir(); … … 26 32 } 27 33 28 $base_filename = TNBU_Utilities::replace_template_vars( TNBU_Core::DEFAULT_DB_FILENAME_TEMPLATE ); 34 if ( null === $filename_template ) { 35 $filename_template = TNBU_Core::DEFAULT_DB_FILENAME_TEMPLATE; 36 } 37 $base_filename = TNBU_Utilities::replace_template_vars( $filename_template ); 29 38 // remove known extensions if user accidentally included them 30 39 $base_filename = preg_replace( '/\.(sql\.gz|zip)$/i', '', $base_filename ); … … 54 63 if ( ! class_exists( 'ZipArchive' ) ) { 55 64 wp_delete_file( $sql_path ); 56 return new WP_Error( ' sbwp_zip', __( 'ZIP extension is not available', 'tiny-backup' ) );65 return new WP_Error( 'tnbu_zip', __( 'ZIP extension is not available', 'tiny-backup' ) ); 57 66 } 58 67 $zip_path = $base_path . $base_filename . '.sql.zip'; … … 61 70 if ( true !== $zip->open( $tmp_path, ZipArchive::CREATE | ZipArchive::OVERWRITE ) ) { 62 71 wp_delete_file( $sql_path ); 63 return new WP_Error( ' sbwp_zip_open', __( 'Failed to create ZIP file', 'tiny-backup' ) );72 return new WP_Error( 'tnbu_zip_open', __( 'Failed to create ZIP file', 'tiny-backup' ) ); 64 73 } 65 74 $zip->addFile( $sql_path, basename( $sql_path ) ); … … 70 79 if ( ! @rename( $tmp_path, $zip_path ) ) { 71 80 wp_delete_file( $tmp_path ); 72 return new WP_Error( ' sbwp_zip_rename', __( 'Failed to finalize ZIP file', 'tiny-backup' ) );81 return new WP_Error( 'tnbu_zip_rename', __( 'Failed to finalize ZIP file', 'tiny-backup' ) ); 73 82 } 74 83 TNBU_Progress_Manager::set_progress( __( 'ZIP compression completed', 'tiny-backup' ), false, null ); … … 90 99 $handle = @fopen( $sql_path, 'wb' ); 91 100 if ( ! $handle ) { 92 return new WP_Error( ' sbwp_phpdump_open', __( 'Unable to write SQL file', 'tiny-backup' ) );101 return new WP_Error( 'tnbu_phpdump_open', __( 'Unable to write SQL file', 'tiny-backup' ) ); 93 102 } 94 103 $site = site_url(); … … 105 114 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Direct file writing for SQL dump 106 115 fclose( $handle ); 107 return new WP_Error( ' sbwp_phpdump_tables', __( 'No tables found', 'tiny-backup' ) );116 return new WP_Error( 'tnbu_phpdump_tables', __( 'No tables found', 'tiny-backup' ) ); 108 117 } 109 118 … … 190 199 fclose( $handle ); 191 200 if ( ! file_exists( $sql_path ) || filesize( $sql_path ) === 0 ) { 192 return new WP_Error( ' sbwp_phpdump_empty', __( 'PHP dump failed (empty file)', 'tiny-backup' ) );201 return new WP_Error( 'tnbu_phpdump_empty', __( 'PHP dump failed (empty file)', 'tiny-backup' ) ); 193 202 } 194 203 return true; -
tiny-backup/tags/1.3.0/includes/class-tnbu-file-backup.php
r3397691 r3487170 15 15 * 指定されたファイル・フォルダをZIP圧縮してバックアップ 16 16 */ 17 public static function perform_files_backup_selected( array $items ) { 17 /** 18 * 指定されたファイル・フォルダをZIP圧縮してバックアップ 19 * 20 * @param array $items バックアップ対象のアイテム 21 * @param string|null $filename_template ファイル名テンプレート(null の場合はデフォルト) 22 * @return string|WP_Error 成功時はファイルパス、失敗時はWP_Error 23 */ 24 public static function perform_files_backup_selected( array $items, $filename_template = null ) { 18 25 $backup_dir = TNBU_Core::get_backup_dir(); 19 26 $ensure = TNBU_Utilities::ensure_directory( $backup_dir ); … … 29 36 @set_time_limit( 0 ); } 30 37 if ( ! class_exists( 'ZipArchive' ) ) { 31 return new WP_Error( ' sbwp_zip', __( 'ZIP extension is not available', 'tiny-backup' ) );38 return new WP_Error( 'tnbu_zip', __( 'ZIP extension is not available', 'tiny-backup' ) ); 32 39 } 33 40 $base = trailingslashit( WP_CONTENT_DIR ); 34 $zip_tmpl = TNBU_Core::DEFAULT_FILES_FILENAME_TEMPLATE;41 $zip_tmpl = null !== $filename_template ? $filename_template : TNBU_Core::DEFAULT_FILES_FILENAME_TEMPLATE; 35 42 $zip_base = TNBU_Utilities::replace_template_vars( strtr( $zip_tmpl, array( '{db}' => ( defined( 'DB_NAME' ) ? DB_NAME : 'wp' ) ) ) ); 36 43 $zip_path = trailingslashit( $backup_dir ) . $zip_base . '.zip'; … … 38 45 $zip = new ZipArchive(); 39 46 if ( true !== $zip->open( $tmp, ZipArchive::CREATE | ZipArchive::OVERWRITE ) ) { 40 return new WP_Error( ' sbwp_zip_open', __( 'Failed to create ZIP file', 'tiny-backup' ) );47 return new WP_Error( 'tnbu_zip_open', __( 'Failed to create ZIP file', 'tiny-backup' ) ); 41 48 } 42 49 $added_any = false; 43 50 $items = array_values( array_unique( $items ) ); 44 $compressed = TNBU_Utilities::optimize_targets_by_parent( $items , $base);51 $compressed = TNBU_Utilities::optimize_targets_by_parent( $items ); 45 52 // ファイルをZIPに追加 46 53 TNBU_Progress_Manager::set_progress( __( 'Starting file scan', 'tiny-backup' ), false, null ); … … 67 74 if ( ! $added_any ) { 68 75 wp_delete_file( $tmp ); 69 return new WP_Error( ' sbwp_files_empty', __( 'No files to add', 'tiny-backup' ) ); }76 return new WP_Error( 'tnbu_files_empty', __( 'No files to add', 'tiny-backup' ) ); } 70 77 // phpcs:ignore WordPress.WP.AlternativeFunctions.rename_rename -- wp_move_file() doesn't exist 71 78 // phpcs:ignore WordPress.WP.AlternativeFunctions.rename_rename -- wp_move_file() doesn't exist 72 79 if ( ! @rename( $tmp, $zip_path ) ) { 73 80 wp_delete_file( $tmp ); 74 return new WP_Error( ' sbwp_zip_finalize', __( 'Failed to finalize ZIP file', 'tiny-backup' ) ); }81 return new WP_Error( 'tnbu_zip_finalize', __( 'Failed to finalize ZIP file', 'tiny-backup' ) ); } 75 82 76 83 TNBU_Progress_Manager::set_progress( __( 'Files compression completed', 'tiny-backup' ), true, null ); … … 115 122 $count = 0; 116 123 $iterator = new RecursiveIteratorIterator( 117 new RecursiveDirectoryIterator( $dir, FilesystemIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS),124 new RecursiveDirectoryIterator( $dir, FilesystemIterator::SKIP_DOTS ), 118 125 RecursiveIteratorIterator::LEAVES_ONLY 119 126 ); … … 151 158 152 159 // 親優先ロジックに基づく最適化:重複する子パスを除去 153 $optimized_targets = TNBU_Utilities::optimize_targets_by_parent( $targets , $base_root);160 $optimized_targets = TNBU_Utilities::optimize_targets_by_parent( $targets ); 154 161 155 162 foreach ( $optimized_targets as $rel ) { … … 183 190 $files = array(); 184 191 $iterator = new RecursiveIteratorIterator( 185 new RecursiveDirectoryIterator( $dir, FilesystemIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS),192 new RecursiveDirectoryIterator( $dir, FilesystemIterator::SKIP_DOTS ), 186 193 RecursiveIteratorIterator::LEAVES_ONLY // ファイルのみ(ディレクトリエントリは不要) 187 194 ); -
tiny-backup/tags/1.3.0/includes/class-tnbu-utilities.php
r3397691 r3487170 156 156 if ( ! is_dir( $dir ) || ! wp_is_writable( $dir ) ) { 157 157 /* translators: %s: directory path */ 158 return new WP_Error( ' sbwp_dir', sprintf( __( 'Cannot write to backup directory: %s', 'tiny-backup' ), $dir ) );158 return new WP_Error( 'tnbu_dir', sprintf( __( 'Cannot write to backup directory: %s', 'tiny-backup' ), $dir ) ); 159 159 } 160 160 return true; -
tiny-backup/tags/1.3.0/languages/tiny-backup-ja-tnbu-admin.json
r3397190 r3487170 23 23 } 24 24 } 25 -
tiny-backup/tags/1.3.0/languages/tiny-backup-ja.po
r3397190 r3487170 3 3 "Project-Id-Version: Tiny Backup 0.1.0\n" 4 4 "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/tiny-backup\n" 5 "POT-Creation-Date: 202 5-10-0900:00+0000\n"6 "PO-Revision-Date: 202 5-10-0900:00+0000\n"5 "POT-Creation-Date: 2026-03-20 00:00+0000\n" 6 "PO-Revision-Date: 2026-03-20 00:00+0000\n" 7 7 "Last-Translator: \n" 8 8 "Language-Team: Japanese\n" … … 21 21 msgstr "最小限の設定でデータベースとファイルのバックアップを作成します。" 22 22 23 #: includes/class- admin-interface.php:6023 #: includes/class-tnbu-admin-interface.php 24 24 msgid "Settings" 25 25 msgstr "設定" 26 26 27 #: includes/class-admin-interface.php:63 28 msgid "Backup targets" 29 msgstr "バックアップ対象" 30 31 #: includes/class-admin-interface.php:68 32 msgid "Select backup items" 33 msgstr "バックアップ項目を選択" 34 35 #: includes/class-admin-interface.php:68 36 msgid "only under wp-content" 37 msgstr "wp-content 配下のみ" 38 39 #: includes/class-admin-interface.php:88 40 msgid "Backup database" 41 msgstr "データベースをバックアップ" 42 43 #: includes/class-admin-interface.php:91 (context: checkbox label) 44 msgctxt "checkbox label" 45 msgid "Backup files" 46 msgstr "ファイルをバックアップ" 47 48 #: includes/class-admin-interface.php:151 27 #: includes/class-tnbu-admin-interface.php 28 msgid "Run backup now" 29 msgstr "今すぐバックアップ" 30 31 #: includes/class-tnbu-cron.php 32 msgid "[%1$s] Tiny Backup: %2$s backup %3$s" 33 msgstr "[%1$s] Tiny Backup: %2$s バックアップ %3$s" 34 35 #: includes/class-tnbu-cron.php 36 msgid "success" 37 msgstr "成功" 38 39 #: includes/class-tnbu-cron.php 40 msgid "failed" 41 msgstr "失敗" 42 43 #: includes/class-tnbu-cron.php 44 msgid "Site: %s" 45 msgstr "サイト: %s" 46 47 #: includes/class-tnbu-cron.php 48 msgid "Backup type: %s" 49 msgstr "バックアップ種別: %s" 50 51 #: includes/class-tnbu-cron.php 52 msgid "Status: %s" 53 msgstr "ステータス: %s" 54 55 #: includes/class-tnbu-cron.php 56 msgid "Time: %s" 57 msgstr "実行日時: %s" 58 59 60 #: includes/class-tnbu-admin-interface.php 61 msgid "Choose what to backup from your uploads folder." 62 msgstr "uploads フォルダからバックアップするファイルを選択" 63 64 #: includes/class-tnbu-admin-interface.php 65 msgid "Auto Backup" 66 msgstr "自動バックアップ" 67 68 #: includes/class-tnbu-admin-interface.php 69 msgid "Database" 70 msgstr "データベース" 71 72 #: includes/class-tnbu-admin-interface.php 73 msgctxt "auto backup setting" 74 msgid "Files" 75 msgstr "ファイル" 76 77 #: includes/class-tnbu-admin-interface.php 78 msgid "Max generations" 79 msgstr "保持世代数" 80 81 #: includes/class-tnbu-admin-interface.php 82 msgid "Email notification" 83 msgstr "メール通知" 84 85 #: includes/class-tnbu-admin-interface.php 86 msgid "On success" 87 msgstr "成功時" 88 89 #: includes/class-tnbu-admin-interface.php 90 msgid "On failure" 91 msgstr "失敗時" 92 93 #: includes/class-tnbu-admin-interface.php 94 msgid "Automatic backups use the same targets as manual backups. Actual execution timing may vary depending on site traffic." 95 msgstr "自動バックアップは手動バックアップと同じ対象を使用します。実際の実行タイミングはサイトへのアクセス状況により前後します。" 96 97 #: includes/class-tnbu-admin-interface.php 98 msgid "Disabled" 99 msgstr "無効" 100 101 #: includes/class-tnbu-admin-interface.php 102 msgid "Daily" 103 msgstr "毎日" 104 105 #: includes/class-tnbu-admin-interface.php 106 msgid "Weekly" 107 msgstr "毎週" 108 109 #: includes/class-tnbu-admin-interface.php 110 msgid "Monthly" 111 msgstr "毎月" 112 113 #: includes/class-tnbu-admin-interface.php 114 msgid "Every Minute (debug)" 115 msgstr "毎分 (デバッグ)" 116 117 #: includes/class-tnbu-admin-interface.php 118 msgid "Sunday" 119 msgstr "日曜日" 120 121 #: includes/class-tnbu-admin-interface.php 122 msgid "Monday" 123 msgstr "月曜日" 124 125 #: includes/class-tnbu-admin-interface.php 126 msgid "Tuesday" 127 msgstr "火曜日" 128 129 #: includes/class-tnbu-admin-interface.php 130 msgid "Wednesday" 131 msgstr "水曜日" 132 133 #: includes/class-tnbu-admin-interface.php 134 msgid "Thursday" 135 msgstr "木曜日" 136 137 #: includes/class-tnbu-admin-interface.php 138 msgid "Friday" 139 msgstr "金曜日" 140 141 #: includes/class-tnbu-admin-interface.php 142 msgid "Saturday" 143 msgstr "土曜日" 144 145 #: includes/class-tnbu-admin-interface.php 146 msgid "day" 147 msgstr "日" 148 149 #. translators: %s: admin email address 150 #: includes/class-tnbu-admin-interface.php 151 msgid "Send notification to %s" 152 msgstr "%s に通知を送信する" 153 154 #: includes/class-tnbu-admin-interface.php 49 155 msgid "Network error occurred" 50 156 msgstr "ネットワークエラーが発生しました" 51 157 52 #: includes/class- admin-interface.php:152158 #: includes/class-tnbu-admin-interface.php 53 159 msgid "Backup failed" 54 160 msgstr "バックアップに失敗しました" 55 161 56 #: includes/class- admin-interface.php:153162 #: includes/class-tnbu-admin-interface.php 57 163 msgid "Backing up" 58 164 msgstr "バックアップ中" 59 165 60 #: includes/class- admin-interface.php:154166 #: includes/class-tnbu-admin-interface.php 61 167 msgid "Starting backup" 62 168 msgstr "バックアップを開始しています" 63 169 64 #: includes/class- admin-interface.php:176170 #: includes/class-tnbu-admin-interface.php 65 171 msgid "Enter a relative path under wp-content (e.g. " 66 172 msgstr "wp-content 配下の相対パスを入力してください (例: " 67 173 68 #: includes/class- admin-interface.php:198174 #: includes/class-tnbu-admin-interface.php 69 175 msgid "Save Settings" 70 176 msgstr "設定を保存" 71 177 72 #: includes/class- admin-interface.php:203178 #: includes/class-tnbu-admin-interface.php 73 179 msgid "Reset settings to defaults? Backup files will not be deleted." 74 180 msgstr "設定を初期値に戻しますか?バックアップファイルは削除されません。" 75 181 76 #: includes/class- admin-interface.php:203182 #: includes/class-tnbu-admin-interface.php 77 183 msgid "Reset settings" 78 184 msgstr "設定をリセット" 79 185 80 #: includes/class- admin-interface.php:209186 #: includes/class-tnbu-admin-interface.php 81 187 msgid "Backup" 82 188 msgstr "バックアップ" 83 189 84 #: includes/class-admin-interface.php:211 85 msgid "Run backup now" 86 msgstr "今すぐバックアップを実行" 87 88 #: includes/class-admin-interface.php:217 190 #: includes/class-tnbu-admin-interface.php 191 msgid "Database backup" 192 msgstr "データベースバックアップ" 193 194 #: includes/class-tnbu-admin-interface.php 195 msgid "Files backup" 196 msgstr "ファイルバックアップ" 197 198 #: includes/class-tnbu-admin-interface.php 89 199 msgid "Backup destination: " 90 200 msgstr "バックアップ保存先: " 91 201 92 #: includes/class- admin-interface.php:221202 #: includes/class-tnbu-admin-interface.php 93 203 msgid "Preparing" 94 204 msgstr "準備中" 95 205 96 #: includes/class- admin-interface.php:229 (context: section title)206 #: includes/class-tnbu-admin-interface.php 97 207 msgctxt "section title" 98 208 msgid "Backup files" 99 209 msgstr "バックアップファイル" 100 210 101 #: includes/class-admin-interface.php:247 102 #: includes/class-admin-interface.php:255 211 #: includes/class-tnbu-admin-interface.php 103 212 msgid "No backup files found" 104 213 msgstr "バックアップファイルが見つかりません" 105 214 106 #: includes/class- admin-interface.php:271215 #: includes/class-tnbu-admin-interface.php 107 216 msgid "Delete the selected files. Are you sure?" 108 217 msgstr "選択したファイルを削除します。よろしいですか?" 109 218 110 #: includes/class- admin-interface.php:277219 #: includes/class-tnbu-admin-interface.php 111 220 msgid "File name" 112 221 msgstr "ファイル名" 113 222 114 #: includes/class- admin-interface.php:278223 #: includes/class-tnbu-admin-interface.php 115 224 msgid "Modified" 116 225 msgstr "更新日時" 117 226 118 #: includes/class- admin-interface.php:279227 #: includes/class-tnbu-admin-interface.php 119 228 msgid "Size" 120 229 msgstr "サイズ" 121 230 122 #: includes/class-admin-interface.php:280 123 #: includes/class-admin-interface.php:298 231 #: includes/class-tnbu-admin-interface.php 124 232 msgid "Download" 125 233 msgstr "ダウンロード" 126 234 127 #: includes/class- admin-interface.php:304235 #: includes/class-tnbu-admin-interface.php 128 236 msgid "Delete selected files" 129 237 msgstr "選択したファイルを削除" 130 238 131 #: includes/class- admin-interface.php:334239 #: includes/class-tnbu-admin-interface.php 132 240 msgid "Settings saved." 133 241 msgstr "設定を保存しました。" 134 242 135 #: includes/class- admin-interface.php:336243 #: includes/class-tnbu-admin-interface.php 136 244 msgid "Dismiss this notice" 137 245 msgstr "この通知を非表示" 138 246 139 #: includes/class-ajax-handler.php:55 140 msgid "Settings saved: DB=%1$s, Files=%2$s" 141 msgstr "設定を保存しました: DB=%1$s, ファイル=%2$s" 142 143 #: includes/class-ajax-handler.php:58 247 #: includes/class-tnbu-ajax-handler.php 144 248 msgid "Backup started" 145 249 msgstr "バックアップを開始しました" 146 250 147 #: includes/class-ajax-handler.php:73 148 msgid "Checking backup settings: DB=%1$s, Files=%2$s" 149 msgstr "バックアップ設定を確認中: DB=%1$s, ファイル=%2$s" 150 151 #: includes/class-ajax-handler.php:76 251 #: includes/class-tnbu-ajax-handler.php 152 252 msgid "Starting database backup" 153 253 msgstr "データベースのバックアップを開始" 154 254 155 #: includes/class-ajax-handler.php:81 255 #. translators: %s: error message 256 #: includes/class-tnbu-ajax-handler.php 156 257 msgid "Database backup error: %s" 157 258 msgstr "データベースのバックアップエラー: %s" 158 259 159 #: includes/class- ajax-handler.php:85260 #: includes/class-tnbu-ajax-handler.php 160 261 msgid "Database backup completed" 161 262 msgstr "データベースのバックアップが完了しました" 162 263 163 #: includes/class- ajax-handler.php:91264 #: includes/class-tnbu-ajax-handler.php 164 265 msgid "Starting files backup" 165 266 msgstr "ファイルのバックアップを開始" 166 267 167 #: includes/class-ajax-handler.php:107 168 msgid "Selected files check: %d items" 169 msgstr "選択ファイルの確認: %d 件" 170 171 #: includes/class-ajax-handler.php:110 268 #: includes/class-tnbu-ajax-handler.php 172 269 msgid "No file targets selected for backup" 173 270 msgstr "バックアップ対象ファイルが選択されていません" 174 271 175 #: includes/class-ajax-handler.php:117 272 #. translators: %s: error message 273 #: includes/class-tnbu-ajax-handler.php 176 274 msgid "Files backup error: %s" 177 275 msgstr "ファイルバックアップのエラー: %s" 178 276 179 #: includes/class-ajax-handler.php:121 180 msgid "Files backup completed: " 181 msgstr "ファイルバックアップ完了: " 182 183 #: includes/class-ajax-handler.php:127 277 #: includes/class-tnbu-ajax-handler.php 278 msgid "Files backup completed" 279 msgstr "ファイルバックアップが完了しました" 280 281 #. translators: %s: error message 282 #: includes/class-tnbu-ajax-handler.php 184 283 msgid "Backup failed: %s" 185 284 msgstr "バックアップに失敗しました: %s" 186 285 187 #: includes/class-ajax-handler.php:129 286 #. translators: %s: error message 287 #: includes/class-tnbu-ajax-handler.php 188 288 msgid "Error: %s" 189 289 msgstr "エラー: %s" 190 290 191 #: includes/class-ajax-handler.php:146 192 msgid "Backup completed: %1$s%2$s" 193 msgstr "バックアップが完了しました: %1$s%2$s" 194 195 #: includes/class-ajax-handler.php:147 291 #. translators: %s: backup file name 292 #: includes/class-tnbu-ajax-handler.php 293 msgid "Backup completed: %s" 294 msgstr "バックアップが完了しました: %s" 295 296 #: includes/class-tnbu-ajax-handler.php 196 297 msgid "Completed" 197 298 msgstr "完了" 198 299 199 #: includes/class- ajax-handler.php:221300 #: includes/class-tnbu-ajax-handler.php 200 301 msgid "You do not have permission." 201 302 msgstr "権限がありません。" 202 303 203 #: includes/class- ajax-handler.php:224304 #: includes/class-tnbu-ajax-handler.php 204 305 msgid "Security check failed." 205 306 msgstr "セキュリティチェックに失敗しました。" 206 307 207 #: includes/class- ajax-handler.php:228308 #: includes/class-tnbu-ajax-handler.php 208 309 msgid "Settings have been reset." 209 310 msgstr "設定を初期化しました。" 210 311 211 #: includes/class- ajax-handler.php:247312 #: includes/class-tnbu-ajax-handler.php 212 313 msgid "No file name specified." 213 314 msgstr "ファイル名が指定されていません。" 214 315 215 #: includes/class- ajax-handler.php:252316 #: includes/class-tnbu-ajax-handler.php 216 317 msgid "Invalid file name." 217 318 msgstr "ファイル名が不正です。" 218 319 219 #: includes/class- ajax-handler.php:265320 #: includes/class-tnbu-ajax-handler.php 220 321 msgid "File not found." 221 322 msgstr "ファイルが見つかりません。" 222 323 223 #: includes/class- ajax-handler.php:272324 #: includes/class-tnbu-ajax-handler.php 224 325 msgid "Invalid file path." 225 326 msgstr "ファイルパスが不正です。" 226 327 227 #: includes/class-database-backup.php:39 328 #: includes/class-tnbu-ajax-handler.php 329 msgid "Selected files have been deleted." 330 msgstr "選択したファイルを削除しました。" 331 332 #: includes/class-tnbu-database-backup.php 228 333 msgid "Starting database dump" 229 334 msgstr "データベースのダンプを開始" 230 335 231 #: includes/class-database-backup.php:42 232 msgid "mysqldump failed, switching to PHP dump" 233 msgstr "mysqldump に失敗したため、PHP ダンプに切り替えます" 234 235 #: includes/class-database-backup.php:49 236 msgid "mysqldump completed" 237 msgstr "mysqldump が完了しました" 238 239 #: includes/class-database-backup.php:59 336 #: includes/class-tnbu-database-backup.php 337 msgid "Database dump completed" 338 msgstr "データベースのダンプが完了しました" 339 340 #: includes/class-tnbu-database-backup.php 240 341 msgid "Starting ZIP compression" 241 342 msgstr "ZIP 圧縮を開始" 242 343 243 #: includes/class- database-backup.php:65344 #: includes/class-tnbu-database-backup.php 244 345 msgid "ZIP extension is not available" 245 346 msgstr "ZIP 拡張が利用できません" 246 347 247 #: includes/class- database-backup.php:73348 #: includes/class-tnbu-database-backup.php 248 349 msgid "Failed to create ZIP file" 249 350 msgstr "ZIP ファイルの作成に失敗しました" 250 351 251 #: includes/class- database-backup.php:82352 #: includes/class-tnbu-database-backup.php 252 353 msgid "Failed to finalize ZIP file" 253 354 msgstr "ZIP ファイルの確定に失敗しました" 254 355 255 #: includes/class- database-backup.php:84356 #: includes/class-tnbu-database-backup.php 256 357 msgid "ZIP compression completed" 257 358 msgstr "ZIP 圧縮が完了しました" 258 359 259 #: includes/class- database-backup.php:102360 #: includes/class-tnbu-database-backup.php 260 361 msgid "Unable to write SQL file" 261 362 msgstr "SQL ファイルを書き込めません" 262 363 263 #: includes/class- database-backup.php:117364 #: includes/class-tnbu-database-backup.php 264 365 msgid "No tables found" 265 366 msgstr "テーブルが見つかりません" 266 367 267 #: includes/class-database-backup.php:126 368 #. translators: 1: table name, 2: current index, 3: total tables 369 #: includes/class-tnbu-database-backup.php 268 370 msgid "Processing table: %1$s (%2$d/%3$d)" 269 371 msgstr "テーブルを処理中: %1$s (%2$d/%3$d)" 270 372 271 #: includes/class-database-backup.php:185 373 #. translators: 1: table name, 2: processed rows, 3: total rows 374 #: includes/class-tnbu-database-backup.php 272 375 msgid "Processing table: %1$s (%2$d/%3$d rows)" 273 376 msgstr "テーブルを処理中: %1$s (%2$d/%3$d 行)" 274 377 275 #: includes/class- database-backup.php:193378 #: includes/class-tnbu-database-backup.php 276 379 msgid "PHP dump failed (empty file)" 277 380 msgstr "PHP ダンプに失敗しました(空のファイル)" 278 381 279 #: includes/class- database-backup.php:207382 #: includes/class-tnbu-database-backup.php 280 383 msgid "Command execution is not allowed on this server" 281 384 msgstr "このサーバーではコマンド実行が許可されていません" 282 385 283 #: includes/class-database-backup.php:247 386 #. translators: %s: error output from mysqldump 387 #: includes/class-tnbu-database-backup.php 284 388 msgid "mysqldump failed: %s" 285 389 msgstr "mysqldump に失敗しました: %s" 286 390 287 288 289 #: includes/class-file-backup.php:44 290 msgid "Trying CLI compression" 291 msgstr "CLI 圧縮を試行中" 292 293 #: includes/class-file-backup.php:47 294 msgid "Files compression completed (CLI)" 295 msgstr "ファイル圧縮が完了しました(CLI)" 296 297 #: includes/class-file-backup.php:50 298 msgid "CLI compression failed, falling back to PHP" 299 msgstr "CLI 圧縮に失敗したため PHP にフォールバックします" 300 301 #: includes/class-file-backup.php:52 391 #: includes/class-tnbu-file-backup.php 302 392 msgid "Starting file scan" 303 393 msgstr "ファイルのスキャンを開始" 304 394 305 #: includes/class-file-backup.php:56 395 #. translators: %d: number of files 396 #: includes/class-tnbu-file-backup.php 306 397 msgid "File scan completed: %d files" 307 398 msgstr "ファイルスキャンが完了: %d 件" 308 399 309 #: includes/class-file-backup.php:63 400 #. translators: 1: processed file count, 2: total files 401 #: includes/class-tnbu-file-backup.php 310 402 msgid "Compressing files: %1$d/%2$d" 311 403 msgstr "ファイルを圧縮中: %1$d/%2$d" 312 404 313 #: includes/class- file-backup.php:68405 #: includes/class-tnbu-file-backup.php 314 406 msgid "No files to add" 315 407 msgstr "追加するファイルがありません" 316 408 317 318 319 #: includes/class-file-backup.php:72 409 #: includes/class-tnbu-file-backup.php 320 410 msgid "Files compression completed" 321 411 msgstr "ファイル圧縮が完了しました" 322 412 323 #: includes/class-progress-manager.php:32 413 #: includes/class-tnbu-cron.php 414 msgid "Once Monthly" 415 msgstr "月1回" 416 417 #: includes/class-tnbu-progress-manager.php 324 418 msgid "Idle" 325 419 msgstr "待機中" 326 420 327 #: includes/class-utilities.php:156 421 #. translators: %s: directory path 422 #: includes/class-tnbu-utilities.php 328 423 msgid "Cannot write to backup directory: %s" 329 424 msgstr "バックアップディレクトリに書き込めません: %s" 330 331 #: includes/class-ajax-handler.php:345332 msgid "Selected files have been deleted."333 msgstr "選択したファイルを削除しました。"334 335 -
tiny-backup/tags/1.3.0/languages/tiny-backup.pot
r3397190 r3487170 48 48 msgstr "" 49 49 50 #: includes/class-admin-interface.php:68 51 msgid "Select backup items" 52 msgstr "" 53 54 #: includes/class-admin-interface.php:68 55 msgid "only under wp-content" 50 #: includes/class-admin-interface.php:199 51 msgid "Choose what to backup from your uploads folder." 56 52 msgstr "" 57 53 -
tiny-backup/tags/1.3.0/readme.txt
r3397693 r3487170 3 3 Tags: backup, database, files, zip, admin 4 4 Requires at least: 6.0 5 Tested up to: 6. 85 Tested up to: 6.9 6 6 Requires PHP: 7.4 7 Stable tag: 1. 1.17 Stable tag: 1.3.0 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html 10 10 11 Simple and minimal backup plugin for WordPress. Create database and files backups with one click.11 Simple and minimal backup plugin for WordPress. Create database and files backups manually or automatically on a schedule. 12 12 13 13 == Description == … … 16 16 You can create and download the bare minimum backup with just one click, stress-free. 17 17 18 - Database backup (SQL inside ZIP) 19 - Files backup (select folders under `wp-content`) 20 - Clear progress indicator and logs 18 **Manual Backup** 19 20 - Database backup (SQL inside ZIP) with a single click 21 - Files backup from your uploads folder — select specific subfolders as needed 22 - Clear progress indicator during backup 23 24 **Auto Backup (WP-Cron)** 25 26 - Set separate schedules for database and files backups (daily / weekly / monthly) 27 - Configure time, day of week, or day of month for each schedule 28 - Manage retention: set max generations for database and files independently 29 - Email notifications on success and/or failure (sent to the admin email address) 30 31 **General** 32 21 33 - No external services; everything runs on your server 34 - Backup files are stored in `wp-content/tiny-backup` 22 35 23 This plugin is ideal for small to medium sites that need quick on-demand backups.36 This plugin is ideal for small to medium sites that need simple, low-overhead backups. 24 37 25 38 == Installation == … … 28 41 2. Activate the plugin through the 'Plugins' screen in WordPress. 29 42 3. Go to Tools → Tiny Backup. 30 4. C hoose backup targets and click "Run backup now".43 4. Click "Database Backup" or "Files Backup" to run a manual backup, or configure Auto Backup settings. 31 44 32 45 == Frequently Asked Questions == … … 34 47 = Where are backups saved? = 35 48 36 B y default, backups are saved to `wp-content/tiny-backup`.49 Backups are saved to `wp-content/tiny-backup` by default. 37 50 38 51 = Can I change the destination directory? = … … 42 55 = Are scheduled backups supported? = 43 56 44 Not currently supported. This initial version only supports manual backups. Scheduled backups may be added in a future version. 57 Yes. As of version 1.3.0, you can configure automatic backups for database and files independently using WP-Cron. Options include daily, weekly, and monthly schedules. 58 59 = Does scheduled backup run at the exact time I set? = 60 61 WP-Cron is triggered by site visits, so the actual execution time may differ slightly from the configured time on low-traffic sites. The backup will run on the next page load after the scheduled time. 62 63 = What folders can I select for file backup? = 64 65 You can select the entire uploads folder or individual subfolders directly under it. Subfolders of subfolders are not selectable. 45 66 46 67 == Screenshots == 47 68 48 1. Settings screen - Choose what to backup: database and/or files, and select specific folders/plugins/themes under wp-content 49 2. Backup management screen - View all backup files with creation date and size, download or delete backups 69 1. Settings screen — Select backup items from the uploads folder 70 2. Auto Backup settings — Configure separate schedules, retention, and email notifications for database and files 71 3. Backup screen — Run manual backups and manage backup files 50 72 51 73 == Changelog == 52 74 53 = 1.1.1 = 75 = 1.3.0 = 76 77 - Added auto backup feature using WP-Cron (daily / weekly / monthly) 78 - Database and files can be scheduled independently 79 - Configurable retention (max generations) per backup type 80 - Email notifications on success and/or failure 81 - Split manual backup into separate "Database Backup" and "Files Backup" buttons 82 - Limited file backup scope to uploads folder (direct subfolders selectable) 83 - Introduced wp-scripts build pipeline for admin assets 84 85 = 1.2.0 = 86 87 - Internal improvements and refactoring. 88 89 = 1.1.1 = 54 90 55 91 - Bug fix. … … 59 95 - Added an action link to the plugin list for quick access to the settings page. 60 96 61 = 1.0.0 = 97 = 1.0.0 = 62 98 63 99 - Initial Release. … … 65 101 == Upgrade Notice == 66 102 67 = 1. 0.0 =103 = 1.3.0 = 68 104 69 - Initial release. 70 71 105 Auto backup, separate DB/files schedules, email notifications, and a redesigned backup UI are now available. -
tiny-backup/tags/1.3.0/tiny-backup.php
r3397693 r3487170 3 3 Plugin Name: Tiny Backup 4 4 Description: Create database and files backups with minimal setup. 5 Version: 1. 1.16 Author: Takashi Fujisaki 5 Version: 1.3.0 6 Author: Takashi Fujisaki 7 7 Plugin URI: https://wordpress.org/plugins/tiny-backup/ 8 8 Author URI: https://yuiami.jp … … 11 11 Requires at least: 6.0 12 12 Requires PHP: 7.4 13 Tested up to: 6. 813 Tested up to: 6.9 14 14 License: GPLv2 or later 15 15 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 28 28 require_once plugin_dir_path( __FILE__ ) . 'includes/class-tnbu-ajax-handler.php'; 29 29 require_once plugin_dir_path( __FILE__ ) . 'includes/class-tnbu-core.php'; 30 require_once plugin_dir_path( __FILE__ ) . 'includes/class-tnbu-cron.php'; 30 31 31 32 32 33 // プラグイン初期化 33 34 TNBU_Core::init(); 35 TNBU_Cron::init(); 36 37 // カスタム cron スケジュール(monthly)を登録 38 add_filter( 'cron_schedules', array( 'TNBU_Cron', 'add_cron_schedules' ) ); 34 39 35 40 // 有効化フック(WPの定石としてメインファイルで登録) 36 41 register_activation_hook( __FILE__, array( 'TNBU_Core', 'on_activate' ) ); 42 43 // 無効化フック(cronスケジュール解除) 44 register_deactivation_hook( __FILE__, array( 'TNBU_Cron', 'unschedule_all' ) ); -
tiny-backup/tags/1.3.0/uninstall.php
r3397693 r3487170 14 14 } 15 15 16 // 定数を利用するため コアクラスを読み込み16 // 定数を利用するためクラスを読み込み 17 17 require_once plugin_dir_path(__FILE__) . 'includes/class-tnbu-core.php'; 18 require_once plugin_dir_path(__FILE__) . 'includes/class-tnbu-cron.php'; 19 20 // cronスケジュールを解除 21 TNBU_Cron::unschedule_all(); 18 22 19 23 // プラグインの設定を削除 -
tiny-backup/trunk/includes/class-tnbu-admin-interface.php
r3397691 r3487170 18 18 $screen = get_current_screen(); 19 19 if ( 'tools_page_tnbu' === $screen->id ) { 20 $asset_file = plugin_dir_path( __DIR__ ) . 'build/admin.asset.php'; 21 $asset = file_exists( $asset_file ) ? require $asset_file : array( 22 'dependencies' => array(), 23 'version' => TNBU_Utilities::get_version(), 24 ); 25 $deps = array_unique( array_merge( $asset['dependencies'], array( 'wp-i18n' ) ) ); 26 20 27 wp_enqueue_style( 21 28 'tnbu-style', 22 plugin_dir_url( __DIR__ ) . ' assets/css/admin.css',29 plugin_dir_url( __DIR__ ) . 'build/admin.css', 23 30 array(), 24 TNBU_Utilities::get_version()31 $asset['version'] 25 32 ); 26 33 wp_enqueue_script( 27 34 'tnbu-admin', 28 plugin_dir_url( __DIR__ ) . ' assets/js/admin.js',29 array( 'wp-i18n' ),30 TNBU_Utilities::get_version(),35 plugin_dir_url( __DIR__ ) . 'build/admin.js', 36 $deps, 37 $asset['version'], 31 38 true 32 39 ); … … 57 64 ); 58 65 wp_add_inline_script( 'tnbu-admin', $inline_script, 'before' ); 66 67 // 自動バックアップUI:スケジュール選択に応じて曜日/日付/時刻の表示切替 68 $auto_backup_script = <<<'JS' 69 document.addEventListener('DOMContentLoaded', function() { 70 document.querySelectorAll('.tnbu-auto-schedule').forEach(function(sel) { 71 sel.addEventListener('change', function() { 72 var row = this.closest('.tnbu-auto-backup-row'); 73 var val = this.value; 74 var dow = row.querySelector('.tnbu-auto-dow'); 75 var day = row.querySelector('.tnbu-auto-day'); 76 var time = row.querySelector('.tnbu-auto-time'); 77 dow.style.display = (val === 'weekly') ? '' : 'none'; 78 day.style.display = (val === 'monthly') ? '' : 'none'; 79 time.style.display = (val === '' || val === 'every_minute') ? 'none' : ''; 80 }); 81 }); 82 }); 83 JS; 84 wp_add_inline_script( 'tnbu-admin', $auto_backup_script, 'after' ); 59 85 } 60 86 } … … 100 126 register_setting( 'tnbu_settings_group', TNBU_Core::OPTION_KEY, array( __CLASS__, 'sanitize_settings' ) ); 101 127 // 単一セクション(見出しなし) 102 add_settings_section( 'tnbu_section_settings', __( 'Settings', 'tiny-backup' ), '__return_false', 'tnbu' ); 103 104 // 最上部: 横並びチェックボックス(DB/ファイル) 105 add_settings_field( 'backup_toggles', __( 'Backup targets', 'tiny-backup' ), array( __CLASS__, 'field_backup_toggles' ), 'tnbu', 'tnbu_section_settings' ); 106 107 // ファイル設定: ファイル名テンプレート(固定のため表示なし) 108 add_settings_field( 109 'files_selection', 110 __( 'Select backup items', 'tiny-backup' ) . '<br>' . __( 'only under wp-content', 'tiny-backup' ), 111 array( __CLASS__, 'field_files_selection' ), 112 'tnbu', 113 'tnbu_section_settings' 114 ); 128 add_settings_section( 'tnbu_section_settings', '', '__return_false', 'tnbu' ); 129 130 // ファイルバックアップ対象選択セクション 131 add_settings_field( 'files_selection', '', array( __CLASS__, 'field_files_selection' ), 'tnbu', 'tnbu_section_files' ); 132 133 // 自動バックアップセクション 134 add_settings_section( 'tnbu_section_auto', __( 'Auto Backup', 'tiny-backup' ), array( __CLASS__, 'section_auto_description' ), 'tnbu' ); 135 add_settings_field( 'auto_backup_db', __( 'Database', 'tiny-backup' ), array( __CLASS__, 'field_auto_backup_db' ), 'tnbu', 'tnbu_section_auto' ); 136 add_settings_field( 'auto_backup_files', _x( 'Files', 'auto backup setting', 'tiny-backup' ), array( __CLASS__, 'field_auto_backup_files' ), 'tnbu', 'tnbu_section_auto' ); 137 add_settings_field( 'auto_backup_email', __( 'Email notification', 'tiny-backup' ), array( __CLASS__, 'field_auto_backup_email' ), 'tnbu', 'tnbu_section_auto' ); 115 138 116 139 // 共通設定: 保存先ディレクトリ(固定化のためUI非表示) 117 }118 119 /**120 * バックアップ対象のトグルボタンを表示121 * データベースとファイルのバックアップ有効/無効を切り替え122 */123 public static function field_backup_toggles() {124 $opts = TNBU_Core::get_options();125 $is_db_backup_enabled = ! empty( $opts['backup_db'] );126 $is_files_backup_enabled = ! empty( $opts['backup_files'] );127 ?>128 <div class="tnbu-backup-toggles">129 <label>130 <input type="checkbox" name="<?php echo esc_attr( TNBU_Core::OPTION_KEY ); ?>[backup_db]" value="1" <?php checked( $is_db_backup_enabled, true ); ?> /> <?php echo esc_html( __( 'Backup database', 'tiny-backup' ) ); ?>131 </label>132 <label>133 <input type="checkbox" name="<?php echo esc_attr( TNBU_Core::OPTION_KEY ); ?>[backup_files]" value="1" <?php checked( $is_files_backup_enabled, true ); ?> /> <?php echo esc_html( _x( 'Backup files', 'checkbox label', 'tiny-backup' ) ); ?>134 </label>135 </div>136 <?php137 140 } 138 141 … … 149 152 $rel = ltrim( $rel, '/' ); 150 153 $output['target_dir'] = ( '' !== $rel ) ? $rel : TNBU_Core::DEFAULT_DIR_SUFFIX; 151 // do not store files filename template152 // backup switches (checkboxes)153 $output['backup_db'] = ! empty( $input['backup_db'] ) ? 1 : 0;154 $output['backup_files'] = ! empty( $input['backup_files'] ) ? 1 : 0;155 154 // save selected items from settings form (if present) 156 155 $sel = isset( $input['selected_items'] ) && is_array( $input['selected_items'] ) ? array_map( 'sanitize_text_field', $input['selected_items'] ) : array(); … … 170 169 ); 171 170 $output['selected_items'] = $sel; 171 172 // 自動バックアップ設定のサニタイズ 173 $valid_schedules = array( '', 'daily', 'weekly', 'monthly' ); 174 if ( defined( 'TNBU_CRON_DEBUG' ) && TNBU_CRON_DEBUG ) { 175 $valid_schedules[] = 'every_minute'; 176 } 177 foreach ( array( 'auto_backup_db', 'auto_backup_files' ) as $prefix ) { 178 $sched = isset( $input[ $prefix . '_schedule' ] ) ? sanitize_text_field( $input[ $prefix . '_schedule' ] ) : ''; 179 $output[ $prefix . '_schedule' ] = in_array( $sched, $valid_schedules, true ) ? $sched : ''; 180 181 $time = isset( $input[ $prefix . '_time' ] ) ? sanitize_text_field( $input[ $prefix . '_time' ] ) : '03:00'; 182 if ( preg_match( '/^(\d{1,2}):(\d{2})$/', $time, $m ) ) { 183 $output[ $prefix . '_time' ] = sprintf( '%02d:%s', max( 0, min( 23, (int) $m[1] ) ), ( (int) $m[2] >= 30 ? '30' : '00' ) ); 184 } else { 185 $output[ $prefix . '_time' ] = '03:00'; 186 } 187 188 $dow = isset( $input[ $prefix . '_day_of_week' ] ) ? (int) $input[ $prefix . '_day_of_week' ] : 0; 189 $output[ $prefix . '_day_of_week' ] = (string) max( 0, min( 6, $dow ) ); 190 191 $day = isset( $input[ $prefix . '_day' ] ) ? (int) $input[ $prefix . '_day' ] : 1; 192 $output[ $prefix . '_day' ] = (string) max( 1, min( 28, $day ) ); 193 } 194 195 $max_gen = isset( $input['auto_backup_db_max_generations'] ) ? (int) $input['auto_backup_db_max_generations'] : TNBU_Core::DEFAULT_AUTO_MAX_GENERATIONS; 196 $output['auto_backup_db_max_generations'] = max( 1, min( 10, $max_gen ) ); 197 198 $max_gen = isset( $input['auto_backup_files_max_generations'] ) ? (int) $input['auto_backup_files_max_generations'] : TNBU_Core::DEFAULT_AUTO_MAX_GENERATIONS; 199 $output['auto_backup_files_max_generations'] = max( 1, min( 10, $max_gen ) ); 200 201 $output['auto_backup_email_success'] = ! empty( $input['auto_backup_email_success'] ); 202 $output['auto_backup_email_failure'] = ! empty( $input['auto_backup_email_failure'] ); 203 172 204 return $output; 173 205 } … … 175 207 /** 176 208 * ファイルバックアップ対象選択UIを表示 177 * wp-content配下のファイル・フォルダをツリー形式で選択可能178 209 */ 179 210 public static function field_files_selection() { … … 184 215 </div> 185 216 </div> 217 218 <hr class="tnbu-divider" /> 219 220 <?php 221 } 222 223 /** 224 * 自動バックアップセクションの説明文 225 */ 226 public static function section_auto_description() { 227 echo '<p class="description">' . esc_html__( 'Automatic backups use the same targets as manual backups. Actual execution timing may vary depending on site traffic.', 'tiny-backup' ) . '</p>'; 228 } 229 230 /** 231 * スケジュール選択肢を返す 232 * 233 * @return array 234 */ 235 private static function get_schedule_options() { 236 $options = array( 237 '' => __( 'Disabled', 'tiny-backup' ), 238 'daily' => __( 'Daily', 'tiny-backup' ), 239 'weekly' => __( 'Weekly', 'tiny-backup' ), 240 'monthly' => __( 'Monthly', 'tiny-backup' ), 241 ); 242 if ( defined( 'TNBU_CRON_DEBUG' ) && TNBU_CRON_DEBUG ) { 243 $options['every_minute'] = __( 'Every Minute (debug)', 'tiny-backup' ); 244 } 245 return $options; 246 } 247 248 /** 249 * 時刻選択肢を返す(0〜23時) 250 * 251 * @return array 252 */ 253 private static function get_time_options() { 254 $times = array(); 255 for ( $h = 0; $h < 24; $h++ ) { 256 foreach ( array( '00', '30' ) as $m ) { 257 $key = sprintf( '%02d:%s', $h, $m ); 258 $times[ $key ] = $key; 259 } 260 } 261 return $times; 262 } 263 264 /** 265 * 曜日選択肢を返す 266 * 267 * @return array 268 */ 269 private static function get_dow_options() { 270 return array( 271 '0' => __( 'Sunday', 'tiny-backup' ), 272 '1' => __( 'Monday', 'tiny-backup' ), 273 '2' => __( 'Tuesday', 'tiny-backup' ), 274 '3' => __( 'Wednesday', 'tiny-backup' ), 275 '4' => __( 'Thursday', 'tiny-backup' ), 276 '5' => __( 'Friday', 'tiny-backup' ), 277 '6' => __( 'Saturday', 'tiny-backup' ), 278 ); 279 } 280 281 /** 282 * 自動バックアップ行(スケジュール+時刻+曜日/日付)をレンダリング 283 * 284 * @param string $prefix 設定キーのプレフィックス('auto_backup_db' or 'auto_backup_files') 285 */ 286 private static function render_auto_backup_row( $prefix ) { 287 $opts = TNBU_Core::get_options(); 288 $opt_key = TNBU_Core::OPTION_KEY; 289 $schedule = $opts[ $prefix . '_schedule' ] ?? ''; 290 $time = $opts[ $prefix . '_time' ] ?? '03'; 291 $dow = $opts[ $prefix . '_day_of_week' ] ?? '0'; 292 $day = $opts[ $prefix . '_day' ] ?? '1'; 293 ?> 294 <div class="tnbu-auto-backup-row" data-prefix="<?php echo esc_attr( $prefix ); ?>"> 295 <select name="<?php echo esc_attr( $opt_key ); ?>[<?php echo esc_attr( $prefix . '_schedule' ); ?>]" class="tnbu-auto-schedule"> 296 <?php foreach ( self::get_schedule_options() as $val => $label ) : ?> 297 <option value="<?php echo esc_attr( $val ); ?>" <?php selected( $schedule, $val ); ?>><?php echo esc_html( $label ); ?></option> 298 <?php endforeach; ?> 299 </select> 300 301 <span class="tnbu-auto-dow" <?php echo 'weekly' !== $schedule ? 'style="display:none;"' : ''; ?>> 302 <select name="<?php echo esc_attr( $opt_key ); ?>[<?php echo esc_attr( $prefix . '_day_of_week' ); ?>]"> 303 <?php foreach ( self::get_dow_options() as $val => $label ) : ?> 304 <option value="<?php echo esc_attr( $val ); ?>" <?php selected( $dow, $val ); ?>><?php echo esc_html( $label ); ?></option> 305 <?php endforeach; ?> 306 </select> 307 </span> 308 309 <span class="tnbu-auto-day" <?php echo 'monthly' !== $schedule ? 'style="display:none;"' : ''; ?>> 310 <select name="<?php echo esc_attr( $opt_key ); ?>[<?php echo esc_attr( $prefix . '_day' ); ?>]"> 311 <?php for ( $d = 1; $d <= 28; $d++ ) : ?> 312 <option value="<?php echo esc_attr( $d ); ?>" <?php selected( $day, (string) $d ); ?>><?php echo esc_html( $d ); ?></option> 313 <?php endfor; ?> 314 </select> 315 <?php echo esc_html__( 'day', 'tiny-backup' ); ?> 316 </span> 317 318 <span class="tnbu-auto-time" <?php echo ( '' === $schedule || 'every_minute' === $schedule ) ? 'style="display:none;"' : ''; ?>> 319 <select name="<?php echo esc_attr( $opt_key ); ?>[<?php echo esc_attr( $prefix . '_time' ); ?>]"> 320 <?php foreach ( self::get_time_options() as $val => $label ) : ?> 321 <option value="<?php echo esc_attr( $val ); ?>" <?php selected( $time, $val ); ?>><?php echo esc_html( $label ); ?></option> 322 <?php endforeach; ?> 323 </select> 324 </span> 325 326 <?php 327 $max_key = $prefix . '_max_generations'; 328 $max_val = $opts[ $max_key ] ?? TNBU_Core::DEFAULT_AUTO_MAX_GENERATIONS; 329 ?> 330 <span class="tnbu-auto-max-gen" <?php echo '' === $schedule ? 'style="display:none;"' : 'style="margin-left:2rem;"'; ?>> 331 <?php echo esc_html__( 'Max generations', 'tiny-backup' ); ?>: 332 <select name="<?php echo esc_attr( $opt_key ); ?>[<?php echo esc_attr( $max_key ); ?>]"> 333 <?php for ( $i = 1; $i <= 10; $i++ ) : ?> 334 <option value="<?php echo esc_attr( $i ); ?>" <?php selected( (int) $max_val, $i ); ?>><?php echo esc_html( $i ); ?></option> 335 <?php endfor; ?> 336 </select> 337 </span> 338 </div> 339 <?php 340 } 341 342 /** 343 * DB自動バックアップ設定フィールド 344 */ 345 public static function field_auto_backup_db() { 346 self::render_auto_backup_row( 'auto_backup_db' ); 347 } 348 349 /** 350 * ファイル自動バックアップ設定フィールド 351 */ 352 public static function field_auto_backup_files() { 353 self::render_auto_backup_row( 'auto_backup_files' ); 354 } 355 356 /** 357 * DB保持世代数設定フィールド 358 */ 359 public static function field_auto_backup_db_max_generations() { 360 $opts = TNBU_Core::get_options(); 361 $max = $opts['auto_backup_db_max_generations'] ?? TNBU_Core::DEFAULT_AUTO_MAX_GENERATIONS; 362 ?> 363 <select name="<?php echo esc_attr( TNBU_Core::OPTION_KEY ); ?>[auto_backup_db_max_generations]"> 364 <?php for ( $i = 1; $i <= 10; $i++ ) : ?> 365 <option value="<?php echo esc_attr( $i ); ?>" <?php selected( (int) $max, $i ); ?>><?php echo esc_html( $i ); ?></option> 366 <?php endfor; ?> 367 </select> 368 <?php 369 } 370 371 /** 372 * ファイル保持世代数設定フィールド 373 */ 374 public static function field_auto_backup_files_max_generations() { 375 $opts = TNBU_Core::get_options(); 376 $max = $opts['auto_backup_files_max_generations'] ?? TNBU_Core::DEFAULT_AUTO_MAX_GENERATIONS; 377 ?> 378 <select name="<?php echo esc_attr( TNBU_Core::OPTION_KEY ); ?>[auto_backup_files_max_generations]"> 379 <?php for ( $i = 1; $i <= 10; $i++ ) : ?> 380 <option value="<?php echo esc_attr( $i ); ?>" <?php selected( (int) $max, $i ); ?>><?php echo esc_html( $i ); ?></option> 381 <?php endfor; ?> 382 </select> 383 <?php 384 } 385 386 /** 387 * メール通知設定フィールド 388 */ 389 public static function field_auto_backup_email() { 390 $opts = TNBU_Core::get_options(); 391 $key = esc_attr( TNBU_Core::OPTION_KEY ); 392 $email = get_option( 'admin_email' ); 393 $success = ! empty( $opts['auto_backup_email_success'] ); 394 $failure = ! empty( $opts['auto_backup_email_failure'] ); 395 ?> 396 <p class="description" style="margin-bottom: 8px;"> 397 <?php echo esc_html( sprintf( 398 /* translators: %s: admin email address */ 399 __( 'Send notification to %s', 'tiny-backup' ), 400 $email 401 ) ); ?> 402 </p> 403 <label style="margin-right: 16px;"> 404 <input type="hidden" name="<?php echo $key; ?>[auto_backup_email_success]" value="0" /> 405 <input type="checkbox" name="<?php echo $key; ?>[auto_backup_email_success]" value="1" <?php checked( $success ); ?> /> 406 <?php echo esc_html__( 'On success', 'tiny-backup' ); ?> 407 </label> 408 <label> 409 <input type="hidden" name="<?php echo $key; ?>[auto_backup_email_failure]" value="0" /> 410 <input type="checkbox" name="<?php echo $key; ?>[auto_backup_email_failure]" value="1" <?php checked( $failure ); ?> /> 411 <?php echo esc_html__( 'On failure', 'tiny-backup' ); ?> 412 </label> 186 413 <?php 187 414 } … … 222 449 223 450 <form id="tnbu-settings-form" class="tnbu-settings-form" method="post" action="options.php"> 451 <h3><?php echo esc_html( __( 'Choose what to backup from your uploads folder.', 'tiny-backup' ) ); ?></h3> 452 <?php self::field_files_selection(); ?> 453 224 454 <?php settings_fields( 'tnbu_settings_group' ); ?> 225 455 <?php do_settings_sections( 'tnbu' ); ?> 226 <?php /* ファイル選択はセクションフィールド側で描画 */ ?>227 456 <?php submit_button( __( 'Save Settings', 'tiny-backup' ) ); ?> 228 457 </form> 458 229 459 <form id="tnbu-reset-form" class="tnbu-reset-form" method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>"> 230 460 <input type="hidden" name="action" value="tnbu_reset_settings" /> … … 236 466 <hr class="tnbu-divider" /> 237 467 238 <h2><?php echo esc_html( __( 'Backup', 'tiny-backup' ) ); ?></h2> 239 <p> 240 <button type="button" class="button button-primary" id="tnbu-backup-button"><?php echo esc_html( __( 'Run backup now', 'tiny-backup' ) ); ?></button> 468 <h2><?php echo esc_html( __( 'Run backup now', 'tiny-backup' ) ); ?></h2> 469 <p class="tnbu-backup-buttons"> 470 <button type="button" class="button button-primary tnbu-backup-trigger" data-backup-type="db"><?php echo esc_html( __( 'Database backup', 'tiny-backup' ) ); ?></button> 471 <button type="button" class="button button-primary tnbu-backup-trigger" data-backup-type="files"><?php echo esc_html( __( 'Files backup', 'tiny-backup' ) ); ?></button> 241 472 </p> 242 473 <?php … … 251 482 </div> 252 483 253 484 <hr class="tnbu-divider" /> 254 485 255 486 <!-- バックアップファイル一覧 --> 256 487 <div class="tnbu-backup-list"> 257 <h 3><?php echo esc_html( _x( 'Backup files', 'section title', 'tiny-backup' ) ); ?></h3>488 <h2><?php echo esc_html( _x( 'Backup files', 'section title', 'tiny-backup' ) ); ?></h2> 258 489 <?php self::render_backup_list(); ?> 259 490 </div> -
tiny-backup/trunk/includes/class-tnbu-ajax-handler.php
r3397691 r3487170 24 24 } 25 25 26 // バックアップ実行前に設定を保存(変更された設定があれば保存する) 27 if ( isset( $_POST['tnbu_backup_db'] ) || isset( $_POST['tnbu_backup_files'] ) ) { 28 $current_opts = TNBU_Core::get_options(); 29 $updated_opts = $current_opts; 30 31 // チェックボックスの状態を更新 32 if ( isset( $_POST['tnbu_backup_db'] ) ) { 33 $updated_opts['backup_db'] = ( sanitize_text_field( wp_unslash( $_POST['tnbu_backup_db'] ) ) === '1' ) ? 1 : 0; 34 } 35 if ( isset( $_POST['tnbu_backup_files'] ) ) { 36 $updated_opts['backup_files'] = ( sanitize_text_field( wp_unslash( $_POST['tnbu_backup_files'] ) ) === '1' ) ? 1 : 0; 37 } 38 39 // 選択されたアイテムを更新(常に更新する、空でも) 40 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized in array_map below 41 $selected = isset( $_POST['tnbu_selected_items'] ) ? (array) wp_unslash( $_POST['tnbu_selected_items'] ) : array(); 42 $selected = array_map( 43 function ( $p ) { 44 return ltrim( (string) sanitize_text_field( $p ), '/' ); 45 }, 46 $selected 47 ); 48 $selected = array_values( 49 array_filter( 50 array_unique( $selected ), 51 function ( $p ) { 52 return '' !== $p && false === strpos( $p, '..' ) && false === strpos( $p, "\0" ); 53 } 54 ) 55 ); 56 // 空の配列でも保存する(選択を解除した場合のため) 57 $updated_opts['selected_items'] = $selected; 58 59 // 設定を保存 60 update_option( TNBU_Core::OPTION_KEY, $updated_opts ); 61 62 /* translators: 1: DB backup enabled (0/1), 2: Files backup enabled (0/1) */ 63 TNBU_Progress_Manager::set_progress( sprintf( __( 'Settings saved: DB=%1$s, Files=%2$s', 'tiny-backup' ), $updated_opts['backup_db'], $updated_opts['backup_files'] ), false, null ); 26 // バックアップ種別を取得('db' or 'files') 27 $backup_type = isset( $_POST['backup_type'] ) ? sanitize_text_field( wp_unslash( $_POST['backup_type'] ) ) : ''; 28 if ( ! in_array( $backup_type, array( 'db', 'files' ), true ) ) { 29 wp_send_json_error( array( 'message' => 'invalid_backup_type' ), 400 ); 64 30 } 65 31 66 32 TNBU_Progress_Manager::set_progress( __( 'Backup started', 'tiny-backup' ), false, null ); 67 // 設定に応じてDB/ファイルのバックアップを実行(キャッシュを強制リフレッシュ) 68 $opts = TNBU_Core::get_options( true ); 69 $last_result_path = ''; 70 $db_result_path = ''; 71 $files_result_path = ''; 72 $error = null; 73 $total_steps = 0; 74 $current_step = 0; 75 76 // 実行するバックアップの種類をカウント 77 if ( ! empty( $opts['backup_db'] ) ) { 78 ++$total_steps; 79 } 80 if ( ! empty( $opts['backup_files'] ) ) { 81 ++$total_steps; 82 } 83 84 /* translators: 1: whether DB backup is enabled (0/1), 2: whether Files backup is enabled (0/1) */ 85 TNBU_Progress_Manager::set_progress( sprintf( __( 'Checking backup settings: DB=%1$s, Files=%2$s', 'tiny-backup' ), $opts['backup_db'], $opts['backup_files'] ), false, null ); 86 87 if ( ! empty( $opts['backup_db'] ) ) { 88 ++$current_step; 33 34 $result_path = ''; 35 $error = null; 36 37 if ( 'db' === $backup_type ) { 89 38 TNBU_Progress_Manager::set_progress( __( 'Starting database backup', 'tiny-backup' ), false, null ); 90 39 $res = TNBU_Database_Backup::perform_backup(); … … 94 43 TNBU_Progress_Manager::set_progress( sprintf( __( 'Database backup error: %s', 'tiny-backup' ), $res->get_error_message() ), false, null ); 95 44 } else { 96 $db_result_path = $res; 97 $last_result_path = $res; 45 $result_path = $res; 98 46 TNBU_Progress_Manager::set_progress( __( 'Database backup completed', 'tiny-backup' ), false, null ); 99 47 } 100 48 } 101 49 102 if ( ! empty( $opts['backup_files'] ) ) { 103 ++$current_step; 50 if ( 'files' === $backup_type ) { 104 51 TNBU_Progress_Manager::set_progress( __( 'Starting files backup', 'tiny-backup' ), false, null ); 105 52 106 // ユーザーが選択した項目があればそれを優先、なければ自動スキャン 107 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized in array_map below 108 $selected = isset( $_POST['tnbu_selected_items'] ) ? (array) wp_unslash( $_POST['tnbu_selected_items'] ) : array(); 109 $selected = array_map( 110 function ( $p ) { 111 return ltrim( (string) sanitize_text_field( $p ), '/' ); 112 }, 113 $selected 114 ); 115 $selected = array_values( 116 array_filter( 117 array_unique( $selected ), 118 function ( $p ) { 119 return '' !== $p && false === strpos( $p, '..' ) && false === strpos( $p, "\0" ); 120 } 121 ) 122 ); 123 if ( empty( $selected ) && ! empty( $opts['selected_items'] ) && is_array( $opts['selected_items'] ) ) { 124 $selected = array_values( 125 array_filter( 126 array_map( 127 function ( $p ) { 128 return ltrim( (string) $p, '/' ); 129 }, 130 $opts['selected_items'] 53 // POSTから選択アイテムを取得、なければ保存済み設定から取得 54 $selected = self::sanitize_selected_items_from_post(); 55 if ( empty( $selected ) ) { 56 $opts = TNBU_Core::get_options( true ); 57 if ( ! empty( $opts['selected_items'] ) && is_array( $opts['selected_items'] ) ) { 58 $selected = array_values( 59 array_filter( 60 array_map( 61 function ( $p ) { 62 return ltrim( (string) $p, '/' ); 63 }, 64 $opts['selected_items'] 65 ) 131 66 ) 132 ) 133 ); 134 } 135 136 /* translators: %d: number of selected items */ 137 TNBU_Progress_Manager::set_progress( sprintf( __( 'Selected files check: %d items', 'tiny-backup' ), count( $selected ) ), false, null ); 67 ); 68 } 69 } 138 70 139 71 if ( empty( $selected ) ) { 140 $fres = new WP_Error( 'tnbu_files_none', __( 'No file targets selected for backup', 'tiny-backup' ) ); 72 $error = new WP_Error( 'tnbu_files_none', __( 'No file targets selected for backup', 'tiny-backup' ) ); 73 TNBU_Progress_Manager::set_progress( $error->get_error_message(), false, null ); 141 74 } else { 142 75 $fres = TNBU_File_Backup::perform_files_backup_selected( $selected ); 143 } 144 if ( is_wp_error( $fres ) ) { 145 $error = $error ? $error : $fres; 146 /* translators: %s: error message */ 147 TNBU_Progress_Manager::set_progress( sprintf( __( 'Files backup error: %s', 'tiny-backup' ), $fres->get_error_message() ), false, null ); 148 } else { 149 $files_result_path = $fres; 150 $last_result_path = $fres; 151 TNBU_Progress_Manager::set_progress( __( 'Files backup completed: ', 'tiny-backup' ), false, null ); 152 } 153 } 154 $result = $error ? $error : ( $last_result_path ? $last_result_path : '' ); 155 if ( is_wp_error( $result ) ) { 76 if ( is_wp_error( $fres ) ) { 77 $error = $fres; 78 /* translators: %s: error message */ 79 TNBU_Progress_Manager::set_progress( sprintf( __( 'Files backup error: %s', 'tiny-backup' ), $fres->get_error_message() ), false, null ); 80 } else { 81 $result_path = $fres; 82 TNBU_Progress_Manager::set_progress( __( 'Files backup completed', 'tiny-backup' ), false, null ); 83 } 84 } 85 } 86 87 if ( $error ) { 156 88 set_transient( 157 89 'tnbu_flash_' . get_current_user_id(), … … 159 91 'type' => 'error', 160 92 /* translators: %s: error message */ 161 'text' => sprintf( __( 'Backup failed: %s', 'tiny-backup' ), $ result->get_error_message() ),93 'text' => sprintf( __( 'Backup failed: %s', 'tiny-backup' ), $error->get_error_message() ), 162 94 ), 163 95 60 164 96 ); 165 97 /* translators: %s: error message */ 166 TNBU_Progress_Manager::set_progress( sprintf( __( 'Error: %s', 'tiny-backup' ), $result->get_error_message() ), true, null ); 167 wp_send_json_error( array( 'message' => $result->get_error_message() ) ); 168 } 169 170 // バックアップ完了メッセージの作成 171 $backup_files = array(); 172 if ( $db_result_path ) { 173 $backup_files[] = basename( $db_result_path ); 174 } 175 if ( $files_result_path ) { 176 $backup_files[] = basename( $files_result_path ); 177 } 178 179 $files_text = implode( ', ', $backup_files ); 180 /* translators: %s: backup file names */ 98 TNBU_Progress_Manager::set_progress( sprintf( __( 'Error: %s', 'tiny-backup' ), $error->get_error_message() ), true, null ); 99 wp_send_json_error( array( 'message' => $error->get_error_message() ) ); 100 } 101 102 /* translators: %s: backup file name */ 181 103 set_transient( 182 104 'tnbu_flash_' . get_current_user_id(), 183 105 array( 184 106 'type' => 'success', 185 /* translators: %s: backup file name s*/186 'text' => sprintf( __( 'Backup completed: %s', 'tiny-backup' ), $files_text),107 /* translators: %s: backup file name */ 108 'text' => sprintf( __( 'Backup completed: %s', 'tiny-backup' ), basename( $result_path ) ), 187 109 ), 188 110 60 189 111 ); 190 112 TNBU_Progress_Manager::set_progress( __( 'Completed', 'tiny-backup' ), true, null ); 191 wp_send_json_success( array( 'path' => $result ) );113 wp_send_json_success( array( 'path' => $result_path ) ); 192 114 } 193 115 … … 214 136 wp_send_json_error( array( 'message' => 'bad_nonce' ), 403 ); 215 137 } 216 $rel = isset( $_POST['path'] ) ? sanitize_text_field( wp_unslash( $_POST['path'] ) ) : ''; 217 $rel = ltrim( $rel, '/' ); 218 $base = trailingslashit( WP_CONTENT_DIR ); 219 $target = $base . $rel; 138 $rel = isset( $_POST['path'] ) ? sanitize_text_field( wp_unslash( $_POST['path'] ) ) : ''; 139 $rel = ltrim( $rel, '/' ); 140 $base = trailingslashit( WP_CONTENT_DIR . '/uploads' ); 141 142 // 1階層のみ表示。pathが空以外の場合は許可しない 143 if ( '' !== $rel ) { 144 wp_send_json_error( array( 'message' => 'depth_limit' ), 400 ); 145 } 146 147 $target = $base; 220 148 $real_base = realpath( $base ); 221 $real_target = realpath( $target ) ? $target : $target; // 未存在でも操作しないのでOK149 $real_target = realpath( $target ) ? $target : $target; 222 150 if ( $real_base && $real_target && 0 !== strpos( wp_normalize_path( $real_target ), wp_normalize_path( $real_base ) ) ) { 223 151 wp_send_json_error( array( 'message' => 'invalid_path' ), 400 ); 224 }225 if ( ! is_dir( $target ) ) {226 $target = $base; // ルート227 152 } 228 153 $items = array(); … … 246 171 $full = $target . DIRECTORY_SEPARATOR . $entry; 247 172 $type = is_dir( $full ) ? 'dir' : 'file'; 248 $relp = ltrim( trim( $rel . '/' . $entry, '/' ) );173 $relp = 'uploads/' . $entry; 249 174 $items[] = array( 250 175 'name' => $entry, … … 353 278 header( 'Pragma: no-cache' ); 354 279 355 // WordPress Filesystem APIを使用してファイル送信 356 if ( ! function_exists( 'WP_Filesystem' ) ) { 357 require_once ABSPATH . 'wp-admin/includes/file.php'; 358 } 359 WP_Filesystem(); 360 global $wp_filesystem; 361 362 if ( ! $wp_filesystem->exists( $file_path ) ) { 363 wp_die( esc_html__( 'File not found.', 'tiny-backup' ) ); 364 } 365 366 $file_content = $wp_filesystem->get_contents( $file_path ); 367 if ( false === $file_content ) { 368 wp_die( esc_html__( 'File read error.', 'tiny-backup' ) ); 369 } 370 371 // チャンクごとに出力 372 $chunk_size = 1024 * 1024; // 1MB 373 $file_length = strlen( $file_content ); 374 for ( $i = 0; $i < $file_length; $i += $chunk_size ) { 375 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Binary file download, escaping would corrupt the data 376 echo substr( $file_content, $i, $chunk_size ); 377 flush(); 378 } 280 // ストリーミングでファイル送信(メモリ節約) 281 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_readfile -- Binary file streaming for download, WP_Filesystem::get_contents() would load entire file into memory 282 readfile( $file_path ); 379 283 exit; 380 284 } 381 285 286 287 /** 288 * POSTデータから選択アイテムをサニタイズして取得する 289 * 290 * @return array サニタイズ済みの選択アイテム配列 291 */ 292 private static function sanitize_selected_items_from_post() { 293 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized in array_map below 294 $selected = isset( $_POST['tnbu_selected_items'] ) ? (array) wp_unslash( $_POST['tnbu_selected_items'] ) : array(); 295 $selected = array_map( 296 function ( $p ) { 297 return ltrim( (string) sanitize_text_field( $p ), '/' ); 298 }, 299 $selected 300 ); 301 return array_values( 302 array_filter( 303 array_unique( $selected ), 304 function ( $p ) { 305 return '' !== $p && false === strpos( $p, '..' ) && false === strpos( $p, "\0" ); 306 } 307 ) 308 ); 309 } 382 310 383 311 /** … … 393 321 $files = isset( $_POST['files'] ) && is_array( $_POST['files'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['files'] ) ) : array(); 394 322 $base = trailingslashit( TNBU_Core::get_backup_dir() ); 395 $deleted = 0;396 323 foreach ( $files as $filename ) { 397 324 if ( ! TNBU_Utilities::validate_backup_filename( $filename ) ) { … … 399 326 } 400 327 $path = $base . $filename; 401 if ( is_file( $path ) && strpos( realpath( $path ), realpath( $base ) ) === 0 && wp_delete_file( $path )) {402 ++$deleted;328 if ( is_file( $path ) && strpos( realpath( $path ), realpath( $base ) ) === 0 ) { 329 wp_delete_file( $path ); 403 330 } 404 331 } -
tiny-backup/trunk/includes/class-tnbu-core.php
r3397691 r3487170 72 72 * @return array デフォルト設定の配列 73 73 */ 74 // 自動バックアップのファイル名テンプレート(-auto 付き) 75 const DEFAULT_AUTO_DB_FILENAME_TEMPLATE = '{db}-{date}-auto-db'; 76 const DEFAULT_AUTO_FILES_FILENAME_TEMPLATE = '{db}-{date}-auto-files'; 77 78 // 自動バックアップの保持世代数デフォルト 79 const DEFAULT_AUTO_MAX_GENERATIONS = 3; 80 74 81 public static function defaults() { 75 82 return array( 76 83 // filename_template is fixed by code to DEFAULT_DB_FILENAME_TEMPLATE 77 84 'target_dir' => self::DEFAULT_DIR_SUFFIX, 78 'backup_db' => 1,79 'backup_files' => 1,80 85 // files filename template is fixed by code to DEFAULT_FILES_FILENAME_TEMPLATE 81 86 'selected_items' => array( 'uploads' ), 87 88 // 自動バックアップ設定 89 'auto_backup_db_schedule' => '', // '' | 'daily' | 'weekly' | 'monthly' 90 'auto_backup_db_time' => '03:00', // '00:00'〜'23:30' 91 'auto_backup_db_day_of_week' => '0', // 0(日)〜6(土) 92 'auto_backup_db_day' => '1', // 1〜28 93 'auto_backup_files_schedule' => '', 94 'auto_backup_files_time' => '03:00', 95 'auto_backup_files_day_of_week' => '0', 96 'auto_backup_files_day' => '1', 97 'auto_backup_db_max_generations' => self::DEFAULT_AUTO_MAX_GENERATIONS, 98 'auto_backup_files_max_generations' => self::DEFAULT_AUTO_MAX_GENERATIONS, 99 'auto_backup_email_success' => false, 100 'auto_backup_email_failure' => false, 82 101 ); 83 102 } … … 116 135 } 117 136 118 /**119 * 設定オプションのキャッシュをクリアする120 * 設定を更新した後に呼び出すことで、次回の get_options() で最新の値を取得できる121 *122 * @return void123 */124 public static function clear_options_cache() {125 // 次回の get_options() で強制的に再読み込みさせるため、引数で制御126 // このメソッドは互換性のために残しているが、get_options(true) を推奨127 }128 137 } -
tiny-backup/trunk/includes/class-tnbu-database-backup.php
r3397691 r3487170 18 18 * @return string|WP_Error 成功時はファイルパス、失敗時はWP_Error 19 19 */ 20 public static function perform_backup() { 20 /** 21 * データベースのバックアップを実行する 22 * 23 * @param string|null $filename_template ファイル名テンプレート(null の場合はデフォルト) 24 * @return string|WP_Error 成功時はファイルパス、失敗時はWP_Error 25 */ 26 public static function perform_backup( $filename_template = null ) { 21 27 global $wpdb; 22 28 $abs_dir = TNBU_Core::get_backup_dir(); … … 26 32 } 27 33 28 $base_filename = TNBU_Utilities::replace_template_vars( TNBU_Core::DEFAULT_DB_FILENAME_TEMPLATE ); 34 if ( null === $filename_template ) { 35 $filename_template = TNBU_Core::DEFAULT_DB_FILENAME_TEMPLATE; 36 } 37 $base_filename = TNBU_Utilities::replace_template_vars( $filename_template ); 29 38 // remove known extensions if user accidentally included them 30 39 $base_filename = preg_replace( '/\.(sql\.gz|zip)$/i', '', $base_filename ); … … 54 63 if ( ! class_exists( 'ZipArchive' ) ) { 55 64 wp_delete_file( $sql_path ); 56 return new WP_Error( ' sbwp_zip', __( 'ZIP extension is not available', 'tiny-backup' ) );65 return new WP_Error( 'tnbu_zip', __( 'ZIP extension is not available', 'tiny-backup' ) ); 57 66 } 58 67 $zip_path = $base_path . $base_filename . '.sql.zip'; … … 61 70 if ( true !== $zip->open( $tmp_path, ZipArchive::CREATE | ZipArchive::OVERWRITE ) ) { 62 71 wp_delete_file( $sql_path ); 63 return new WP_Error( ' sbwp_zip_open', __( 'Failed to create ZIP file', 'tiny-backup' ) );72 return new WP_Error( 'tnbu_zip_open', __( 'Failed to create ZIP file', 'tiny-backup' ) ); 64 73 } 65 74 $zip->addFile( $sql_path, basename( $sql_path ) ); … … 70 79 if ( ! @rename( $tmp_path, $zip_path ) ) { 71 80 wp_delete_file( $tmp_path ); 72 return new WP_Error( ' sbwp_zip_rename', __( 'Failed to finalize ZIP file', 'tiny-backup' ) );81 return new WP_Error( 'tnbu_zip_rename', __( 'Failed to finalize ZIP file', 'tiny-backup' ) ); 73 82 } 74 83 TNBU_Progress_Manager::set_progress( __( 'ZIP compression completed', 'tiny-backup' ), false, null ); … … 90 99 $handle = @fopen( $sql_path, 'wb' ); 91 100 if ( ! $handle ) { 92 return new WP_Error( ' sbwp_phpdump_open', __( 'Unable to write SQL file', 'tiny-backup' ) );101 return new WP_Error( 'tnbu_phpdump_open', __( 'Unable to write SQL file', 'tiny-backup' ) ); 93 102 } 94 103 $site = site_url(); … … 105 114 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Direct file writing for SQL dump 106 115 fclose( $handle ); 107 return new WP_Error( ' sbwp_phpdump_tables', __( 'No tables found', 'tiny-backup' ) );116 return new WP_Error( 'tnbu_phpdump_tables', __( 'No tables found', 'tiny-backup' ) ); 108 117 } 109 118 … … 190 199 fclose( $handle ); 191 200 if ( ! file_exists( $sql_path ) || filesize( $sql_path ) === 0 ) { 192 return new WP_Error( ' sbwp_phpdump_empty', __( 'PHP dump failed (empty file)', 'tiny-backup' ) );201 return new WP_Error( 'tnbu_phpdump_empty', __( 'PHP dump failed (empty file)', 'tiny-backup' ) ); 193 202 } 194 203 return true; -
tiny-backup/trunk/includes/class-tnbu-file-backup.php
r3397691 r3487170 15 15 * 指定されたファイル・フォルダをZIP圧縮してバックアップ 16 16 */ 17 public static function perform_files_backup_selected( array $items ) { 17 /** 18 * 指定されたファイル・フォルダをZIP圧縮してバックアップ 19 * 20 * @param array $items バックアップ対象のアイテム 21 * @param string|null $filename_template ファイル名テンプレート(null の場合はデフォルト) 22 * @return string|WP_Error 成功時はファイルパス、失敗時はWP_Error 23 */ 24 public static function perform_files_backup_selected( array $items, $filename_template = null ) { 18 25 $backup_dir = TNBU_Core::get_backup_dir(); 19 26 $ensure = TNBU_Utilities::ensure_directory( $backup_dir ); … … 29 36 @set_time_limit( 0 ); } 30 37 if ( ! class_exists( 'ZipArchive' ) ) { 31 return new WP_Error( ' sbwp_zip', __( 'ZIP extension is not available', 'tiny-backup' ) );38 return new WP_Error( 'tnbu_zip', __( 'ZIP extension is not available', 'tiny-backup' ) ); 32 39 } 33 40 $base = trailingslashit( WP_CONTENT_DIR ); 34 $zip_tmpl = TNBU_Core::DEFAULT_FILES_FILENAME_TEMPLATE;41 $zip_tmpl = null !== $filename_template ? $filename_template : TNBU_Core::DEFAULT_FILES_FILENAME_TEMPLATE; 35 42 $zip_base = TNBU_Utilities::replace_template_vars( strtr( $zip_tmpl, array( '{db}' => ( defined( 'DB_NAME' ) ? DB_NAME : 'wp' ) ) ) ); 36 43 $zip_path = trailingslashit( $backup_dir ) . $zip_base . '.zip'; … … 38 45 $zip = new ZipArchive(); 39 46 if ( true !== $zip->open( $tmp, ZipArchive::CREATE | ZipArchive::OVERWRITE ) ) { 40 return new WP_Error( ' sbwp_zip_open', __( 'Failed to create ZIP file', 'tiny-backup' ) );47 return new WP_Error( 'tnbu_zip_open', __( 'Failed to create ZIP file', 'tiny-backup' ) ); 41 48 } 42 49 $added_any = false; 43 50 $items = array_values( array_unique( $items ) ); 44 $compressed = TNBU_Utilities::optimize_targets_by_parent( $items , $base);51 $compressed = TNBU_Utilities::optimize_targets_by_parent( $items ); 45 52 // ファイルをZIPに追加 46 53 TNBU_Progress_Manager::set_progress( __( 'Starting file scan', 'tiny-backup' ), false, null ); … … 67 74 if ( ! $added_any ) { 68 75 wp_delete_file( $tmp ); 69 return new WP_Error( ' sbwp_files_empty', __( 'No files to add', 'tiny-backup' ) ); }76 return new WP_Error( 'tnbu_files_empty', __( 'No files to add', 'tiny-backup' ) ); } 70 77 // phpcs:ignore WordPress.WP.AlternativeFunctions.rename_rename -- wp_move_file() doesn't exist 71 78 // phpcs:ignore WordPress.WP.AlternativeFunctions.rename_rename -- wp_move_file() doesn't exist 72 79 if ( ! @rename( $tmp, $zip_path ) ) { 73 80 wp_delete_file( $tmp ); 74 return new WP_Error( ' sbwp_zip_finalize', __( 'Failed to finalize ZIP file', 'tiny-backup' ) ); }81 return new WP_Error( 'tnbu_zip_finalize', __( 'Failed to finalize ZIP file', 'tiny-backup' ) ); } 75 82 76 83 TNBU_Progress_Manager::set_progress( __( 'Files compression completed', 'tiny-backup' ), true, null ); … … 115 122 $count = 0; 116 123 $iterator = new RecursiveIteratorIterator( 117 new RecursiveDirectoryIterator( $dir, FilesystemIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS),124 new RecursiveDirectoryIterator( $dir, FilesystemIterator::SKIP_DOTS ), 118 125 RecursiveIteratorIterator::LEAVES_ONLY 119 126 ); … … 151 158 152 159 // 親優先ロジックに基づく最適化:重複する子パスを除去 153 $optimized_targets = TNBU_Utilities::optimize_targets_by_parent( $targets , $base_root);160 $optimized_targets = TNBU_Utilities::optimize_targets_by_parent( $targets ); 154 161 155 162 foreach ( $optimized_targets as $rel ) { … … 183 190 $files = array(); 184 191 $iterator = new RecursiveIteratorIterator( 185 new RecursiveDirectoryIterator( $dir, FilesystemIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS),192 new RecursiveDirectoryIterator( $dir, FilesystemIterator::SKIP_DOTS ), 186 193 RecursiveIteratorIterator::LEAVES_ONLY // ファイルのみ(ディレクトリエントリは不要) 187 194 ); -
tiny-backup/trunk/includes/class-tnbu-utilities.php
r3397691 r3487170 156 156 if ( ! is_dir( $dir ) || ! wp_is_writable( $dir ) ) { 157 157 /* translators: %s: directory path */ 158 return new WP_Error( ' sbwp_dir', sprintf( __( 'Cannot write to backup directory: %s', 'tiny-backup' ), $dir ) );158 return new WP_Error( 'tnbu_dir', sprintf( __( 'Cannot write to backup directory: %s', 'tiny-backup' ), $dir ) ); 159 159 } 160 160 return true; -
tiny-backup/trunk/languages/tiny-backup-ja-tnbu-admin.json
r3397190 r3487170 23 23 } 24 24 } 25 -
tiny-backup/trunk/languages/tiny-backup-ja.po
r3397190 r3487170 3 3 "Project-Id-Version: Tiny Backup 0.1.0\n" 4 4 "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/tiny-backup\n" 5 "POT-Creation-Date: 202 5-10-0900:00+0000\n"6 "PO-Revision-Date: 202 5-10-0900:00+0000\n"5 "POT-Creation-Date: 2026-03-20 00:00+0000\n" 6 "PO-Revision-Date: 2026-03-20 00:00+0000\n" 7 7 "Last-Translator: \n" 8 8 "Language-Team: Japanese\n" … … 21 21 msgstr "最小限の設定でデータベースとファイルのバックアップを作成します。" 22 22 23 #: includes/class- admin-interface.php:6023 #: includes/class-tnbu-admin-interface.php 24 24 msgid "Settings" 25 25 msgstr "設定" 26 26 27 #: includes/class-admin-interface.php:63 28 msgid "Backup targets" 29 msgstr "バックアップ対象" 30 31 #: includes/class-admin-interface.php:68 32 msgid "Select backup items" 33 msgstr "バックアップ項目を選択" 34 35 #: includes/class-admin-interface.php:68 36 msgid "only under wp-content" 37 msgstr "wp-content 配下のみ" 38 39 #: includes/class-admin-interface.php:88 40 msgid "Backup database" 41 msgstr "データベースをバックアップ" 42 43 #: includes/class-admin-interface.php:91 (context: checkbox label) 44 msgctxt "checkbox label" 45 msgid "Backup files" 46 msgstr "ファイルをバックアップ" 47 48 #: includes/class-admin-interface.php:151 27 #: includes/class-tnbu-admin-interface.php 28 msgid "Run backup now" 29 msgstr "今すぐバックアップ" 30 31 #: includes/class-tnbu-cron.php 32 msgid "[%1$s] Tiny Backup: %2$s backup %3$s" 33 msgstr "[%1$s] Tiny Backup: %2$s バックアップ %3$s" 34 35 #: includes/class-tnbu-cron.php 36 msgid "success" 37 msgstr "成功" 38 39 #: includes/class-tnbu-cron.php 40 msgid "failed" 41 msgstr "失敗" 42 43 #: includes/class-tnbu-cron.php 44 msgid "Site: %s" 45 msgstr "サイト: %s" 46 47 #: includes/class-tnbu-cron.php 48 msgid "Backup type: %s" 49 msgstr "バックアップ種別: %s" 50 51 #: includes/class-tnbu-cron.php 52 msgid "Status: %s" 53 msgstr "ステータス: %s" 54 55 #: includes/class-tnbu-cron.php 56 msgid "Time: %s" 57 msgstr "実行日時: %s" 58 59 60 #: includes/class-tnbu-admin-interface.php 61 msgid "Choose what to backup from your uploads folder." 62 msgstr "uploads フォルダからバックアップするファイルを選択" 63 64 #: includes/class-tnbu-admin-interface.php 65 msgid "Auto Backup" 66 msgstr "自動バックアップ" 67 68 #: includes/class-tnbu-admin-interface.php 69 msgid "Database" 70 msgstr "データベース" 71 72 #: includes/class-tnbu-admin-interface.php 73 msgctxt "auto backup setting" 74 msgid "Files" 75 msgstr "ファイル" 76 77 #: includes/class-tnbu-admin-interface.php 78 msgid "Max generations" 79 msgstr "保持世代数" 80 81 #: includes/class-tnbu-admin-interface.php 82 msgid "Email notification" 83 msgstr "メール通知" 84 85 #: includes/class-tnbu-admin-interface.php 86 msgid "On success" 87 msgstr "成功時" 88 89 #: includes/class-tnbu-admin-interface.php 90 msgid "On failure" 91 msgstr "失敗時" 92 93 #: includes/class-tnbu-admin-interface.php 94 msgid "Automatic backups use the same targets as manual backups. Actual execution timing may vary depending on site traffic." 95 msgstr "自動バックアップは手動バックアップと同じ対象を使用します。実際の実行タイミングはサイトへのアクセス状況により前後します。" 96 97 #: includes/class-tnbu-admin-interface.php 98 msgid "Disabled" 99 msgstr "無効" 100 101 #: includes/class-tnbu-admin-interface.php 102 msgid "Daily" 103 msgstr "毎日" 104 105 #: includes/class-tnbu-admin-interface.php 106 msgid "Weekly" 107 msgstr "毎週" 108 109 #: includes/class-tnbu-admin-interface.php 110 msgid "Monthly" 111 msgstr "毎月" 112 113 #: includes/class-tnbu-admin-interface.php 114 msgid "Every Minute (debug)" 115 msgstr "毎分 (デバッグ)" 116 117 #: includes/class-tnbu-admin-interface.php 118 msgid "Sunday" 119 msgstr "日曜日" 120 121 #: includes/class-tnbu-admin-interface.php 122 msgid "Monday" 123 msgstr "月曜日" 124 125 #: includes/class-tnbu-admin-interface.php 126 msgid "Tuesday" 127 msgstr "火曜日" 128 129 #: includes/class-tnbu-admin-interface.php 130 msgid "Wednesday" 131 msgstr "水曜日" 132 133 #: includes/class-tnbu-admin-interface.php 134 msgid "Thursday" 135 msgstr "木曜日" 136 137 #: includes/class-tnbu-admin-interface.php 138 msgid "Friday" 139 msgstr "金曜日" 140 141 #: includes/class-tnbu-admin-interface.php 142 msgid "Saturday" 143 msgstr "土曜日" 144 145 #: includes/class-tnbu-admin-interface.php 146 msgid "day" 147 msgstr "日" 148 149 #. translators: %s: admin email address 150 #: includes/class-tnbu-admin-interface.php 151 msgid "Send notification to %s" 152 msgstr "%s に通知を送信する" 153 154 #: includes/class-tnbu-admin-interface.php 49 155 msgid "Network error occurred" 50 156 msgstr "ネットワークエラーが発生しました" 51 157 52 #: includes/class- admin-interface.php:152158 #: includes/class-tnbu-admin-interface.php 53 159 msgid "Backup failed" 54 160 msgstr "バックアップに失敗しました" 55 161 56 #: includes/class- admin-interface.php:153162 #: includes/class-tnbu-admin-interface.php 57 163 msgid "Backing up" 58 164 msgstr "バックアップ中" 59 165 60 #: includes/class- admin-interface.php:154166 #: includes/class-tnbu-admin-interface.php 61 167 msgid "Starting backup" 62 168 msgstr "バックアップを開始しています" 63 169 64 #: includes/class- admin-interface.php:176170 #: includes/class-tnbu-admin-interface.php 65 171 msgid "Enter a relative path under wp-content (e.g. " 66 172 msgstr "wp-content 配下の相対パスを入力してください (例: " 67 173 68 #: includes/class- admin-interface.php:198174 #: includes/class-tnbu-admin-interface.php 69 175 msgid "Save Settings" 70 176 msgstr "設定を保存" 71 177 72 #: includes/class- admin-interface.php:203178 #: includes/class-tnbu-admin-interface.php 73 179 msgid "Reset settings to defaults? Backup files will not be deleted." 74 180 msgstr "設定を初期値に戻しますか?バックアップファイルは削除されません。" 75 181 76 #: includes/class- admin-interface.php:203182 #: includes/class-tnbu-admin-interface.php 77 183 msgid "Reset settings" 78 184 msgstr "設定をリセット" 79 185 80 #: includes/class- admin-interface.php:209186 #: includes/class-tnbu-admin-interface.php 81 187 msgid "Backup" 82 188 msgstr "バックアップ" 83 189 84 #: includes/class-admin-interface.php:211 85 msgid "Run backup now" 86 msgstr "今すぐバックアップを実行" 87 88 #: includes/class-admin-interface.php:217 190 #: includes/class-tnbu-admin-interface.php 191 msgid "Database backup" 192 msgstr "データベースバックアップ" 193 194 #: includes/class-tnbu-admin-interface.php 195 msgid "Files backup" 196 msgstr "ファイルバックアップ" 197 198 #: includes/class-tnbu-admin-interface.php 89 199 msgid "Backup destination: " 90 200 msgstr "バックアップ保存先: " 91 201 92 #: includes/class- admin-interface.php:221202 #: includes/class-tnbu-admin-interface.php 93 203 msgid "Preparing" 94 204 msgstr "準備中" 95 205 96 #: includes/class- admin-interface.php:229 (context: section title)206 #: includes/class-tnbu-admin-interface.php 97 207 msgctxt "section title" 98 208 msgid "Backup files" 99 209 msgstr "バックアップファイル" 100 210 101 #: includes/class-admin-interface.php:247 102 #: includes/class-admin-interface.php:255 211 #: includes/class-tnbu-admin-interface.php 103 212 msgid "No backup files found" 104 213 msgstr "バックアップファイルが見つかりません" 105 214 106 #: includes/class- admin-interface.php:271215 #: includes/class-tnbu-admin-interface.php 107 216 msgid "Delete the selected files. Are you sure?" 108 217 msgstr "選択したファイルを削除します。よろしいですか?" 109 218 110 #: includes/class- admin-interface.php:277219 #: includes/class-tnbu-admin-interface.php 111 220 msgid "File name" 112 221 msgstr "ファイル名" 113 222 114 #: includes/class- admin-interface.php:278223 #: includes/class-tnbu-admin-interface.php 115 224 msgid "Modified" 116 225 msgstr "更新日時" 117 226 118 #: includes/class- admin-interface.php:279227 #: includes/class-tnbu-admin-interface.php 119 228 msgid "Size" 120 229 msgstr "サイズ" 121 230 122 #: includes/class-admin-interface.php:280 123 #: includes/class-admin-interface.php:298 231 #: includes/class-tnbu-admin-interface.php 124 232 msgid "Download" 125 233 msgstr "ダウンロード" 126 234 127 #: includes/class- admin-interface.php:304235 #: includes/class-tnbu-admin-interface.php 128 236 msgid "Delete selected files" 129 237 msgstr "選択したファイルを削除" 130 238 131 #: includes/class- admin-interface.php:334239 #: includes/class-tnbu-admin-interface.php 132 240 msgid "Settings saved." 133 241 msgstr "設定を保存しました。" 134 242 135 #: includes/class- admin-interface.php:336243 #: includes/class-tnbu-admin-interface.php 136 244 msgid "Dismiss this notice" 137 245 msgstr "この通知を非表示" 138 246 139 #: includes/class-ajax-handler.php:55 140 msgid "Settings saved: DB=%1$s, Files=%2$s" 141 msgstr "設定を保存しました: DB=%1$s, ファイル=%2$s" 142 143 #: includes/class-ajax-handler.php:58 247 #: includes/class-tnbu-ajax-handler.php 144 248 msgid "Backup started" 145 249 msgstr "バックアップを開始しました" 146 250 147 #: includes/class-ajax-handler.php:73 148 msgid "Checking backup settings: DB=%1$s, Files=%2$s" 149 msgstr "バックアップ設定を確認中: DB=%1$s, ファイル=%2$s" 150 151 #: includes/class-ajax-handler.php:76 251 #: includes/class-tnbu-ajax-handler.php 152 252 msgid "Starting database backup" 153 253 msgstr "データベースのバックアップを開始" 154 254 155 #: includes/class-ajax-handler.php:81 255 #. translators: %s: error message 256 #: includes/class-tnbu-ajax-handler.php 156 257 msgid "Database backup error: %s" 157 258 msgstr "データベースのバックアップエラー: %s" 158 259 159 #: includes/class- ajax-handler.php:85260 #: includes/class-tnbu-ajax-handler.php 160 261 msgid "Database backup completed" 161 262 msgstr "データベースのバックアップが完了しました" 162 263 163 #: includes/class- ajax-handler.php:91264 #: includes/class-tnbu-ajax-handler.php 164 265 msgid "Starting files backup" 165 266 msgstr "ファイルのバックアップを開始" 166 267 167 #: includes/class-ajax-handler.php:107 168 msgid "Selected files check: %d items" 169 msgstr "選択ファイルの確認: %d 件" 170 171 #: includes/class-ajax-handler.php:110 268 #: includes/class-tnbu-ajax-handler.php 172 269 msgid "No file targets selected for backup" 173 270 msgstr "バックアップ対象ファイルが選択されていません" 174 271 175 #: includes/class-ajax-handler.php:117 272 #. translators: %s: error message 273 #: includes/class-tnbu-ajax-handler.php 176 274 msgid "Files backup error: %s" 177 275 msgstr "ファイルバックアップのエラー: %s" 178 276 179 #: includes/class-ajax-handler.php:121 180 msgid "Files backup completed: " 181 msgstr "ファイルバックアップ完了: " 182 183 #: includes/class-ajax-handler.php:127 277 #: includes/class-tnbu-ajax-handler.php 278 msgid "Files backup completed" 279 msgstr "ファイルバックアップが完了しました" 280 281 #. translators: %s: error message 282 #: includes/class-tnbu-ajax-handler.php 184 283 msgid "Backup failed: %s" 185 284 msgstr "バックアップに失敗しました: %s" 186 285 187 #: includes/class-ajax-handler.php:129 286 #. translators: %s: error message 287 #: includes/class-tnbu-ajax-handler.php 188 288 msgid "Error: %s" 189 289 msgstr "エラー: %s" 190 290 191 #: includes/class-ajax-handler.php:146 192 msgid "Backup completed: %1$s%2$s" 193 msgstr "バックアップが完了しました: %1$s%2$s" 194 195 #: includes/class-ajax-handler.php:147 291 #. translators: %s: backup file name 292 #: includes/class-tnbu-ajax-handler.php 293 msgid "Backup completed: %s" 294 msgstr "バックアップが完了しました: %s" 295 296 #: includes/class-tnbu-ajax-handler.php 196 297 msgid "Completed" 197 298 msgstr "完了" 198 299 199 #: includes/class- ajax-handler.php:221300 #: includes/class-tnbu-ajax-handler.php 200 301 msgid "You do not have permission." 201 302 msgstr "権限がありません。" 202 303 203 #: includes/class- ajax-handler.php:224304 #: includes/class-tnbu-ajax-handler.php 204 305 msgid "Security check failed." 205 306 msgstr "セキュリティチェックに失敗しました。" 206 307 207 #: includes/class- ajax-handler.php:228308 #: includes/class-tnbu-ajax-handler.php 208 309 msgid "Settings have been reset." 209 310 msgstr "設定を初期化しました。" 210 311 211 #: includes/class- ajax-handler.php:247312 #: includes/class-tnbu-ajax-handler.php 212 313 msgid "No file name specified." 213 314 msgstr "ファイル名が指定されていません。" 214 315 215 #: includes/class- ajax-handler.php:252316 #: includes/class-tnbu-ajax-handler.php 216 317 msgid "Invalid file name." 217 318 msgstr "ファイル名が不正です。" 218 319 219 #: includes/class- ajax-handler.php:265320 #: includes/class-tnbu-ajax-handler.php 220 321 msgid "File not found." 221 322 msgstr "ファイルが見つかりません。" 222 323 223 #: includes/class- ajax-handler.php:272324 #: includes/class-tnbu-ajax-handler.php 224 325 msgid "Invalid file path." 225 326 msgstr "ファイルパスが不正です。" 226 327 227 #: includes/class-database-backup.php:39 328 #: includes/class-tnbu-ajax-handler.php 329 msgid "Selected files have been deleted." 330 msgstr "選択したファイルを削除しました。" 331 332 #: includes/class-tnbu-database-backup.php 228 333 msgid "Starting database dump" 229 334 msgstr "データベースのダンプを開始" 230 335 231 #: includes/class-database-backup.php:42 232 msgid "mysqldump failed, switching to PHP dump" 233 msgstr "mysqldump に失敗したため、PHP ダンプに切り替えます" 234 235 #: includes/class-database-backup.php:49 236 msgid "mysqldump completed" 237 msgstr "mysqldump が完了しました" 238 239 #: includes/class-database-backup.php:59 336 #: includes/class-tnbu-database-backup.php 337 msgid "Database dump completed" 338 msgstr "データベースのダンプが完了しました" 339 340 #: includes/class-tnbu-database-backup.php 240 341 msgid "Starting ZIP compression" 241 342 msgstr "ZIP 圧縮を開始" 242 343 243 #: includes/class- database-backup.php:65344 #: includes/class-tnbu-database-backup.php 244 345 msgid "ZIP extension is not available" 245 346 msgstr "ZIP 拡張が利用できません" 246 347 247 #: includes/class- database-backup.php:73348 #: includes/class-tnbu-database-backup.php 248 349 msgid "Failed to create ZIP file" 249 350 msgstr "ZIP ファイルの作成に失敗しました" 250 351 251 #: includes/class- database-backup.php:82352 #: includes/class-tnbu-database-backup.php 252 353 msgid "Failed to finalize ZIP file" 253 354 msgstr "ZIP ファイルの確定に失敗しました" 254 355 255 #: includes/class- database-backup.php:84356 #: includes/class-tnbu-database-backup.php 256 357 msgid "ZIP compression completed" 257 358 msgstr "ZIP 圧縮が完了しました" 258 359 259 #: includes/class- database-backup.php:102360 #: includes/class-tnbu-database-backup.php 260 361 msgid "Unable to write SQL file" 261 362 msgstr "SQL ファイルを書き込めません" 262 363 263 #: includes/class- database-backup.php:117364 #: includes/class-tnbu-database-backup.php 264 365 msgid "No tables found" 265 366 msgstr "テーブルが見つかりません" 266 367 267 #: includes/class-database-backup.php:126 368 #. translators: 1: table name, 2: current index, 3: total tables 369 #: includes/class-tnbu-database-backup.php 268 370 msgid "Processing table: %1$s (%2$d/%3$d)" 269 371 msgstr "テーブルを処理中: %1$s (%2$d/%3$d)" 270 372 271 #: includes/class-database-backup.php:185 373 #. translators: 1: table name, 2: processed rows, 3: total rows 374 #: includes/class-tnbu-database-backup.php 272 375 msgid "Processing table: %1$s (%2$d/%3$d rows)" 273 376 msgstr "テーブルを処理中: %1$s (%2$d/%3$d 行)" 274 377 275 #: includes/class- database-backup.php:193378 #: includes/class-tnbu-database-backup.php 276 379 msgid "PHP dump failed (empty file)" 277 380 msgstr "PHP ダンプに失敗しました(空のファイル)" 278 381 279 #: includes/class- database-backup.php:207382 #: includes/class-tnbu-database-backup.php 280 383 msgid "Command execution is not allowed on this server" 281 384 msgstr "このサーバーではコマンド実行が許可されていません" 282 385 283 #: includes/class-database-backup.php:247 386 #. translators: %s: error output from mysqldump 387 #: includes/class-tnbu-database-backup.php 284 388 msgid "mysqldump failed: %s" 285 389 msgstr "mysqldump に失敗しました: %s" 286 390 287 288 289 #: includes/class-file-backup.php:44 290 msgid "Trying CLI compression" 291 msgstr "CLI 圧縮を試行中" 292 293 #: includes/class-file-backup.php:47 294 msgid "Files compression completed (CLI)" 295 msgstr "ファイル圧縮が完了しました(CLI)" 296 297 #: includes/class-file-backup.php:50 298 msgid "CLI compression failed, falling back to PHP" 299 msgstr "CLI 圧縮に失敗したため PHP にフォールバックします" 300 301 #: includes/class-file-backup.php:52 391 #: includes/class-tnbu-file-backup.php 302 392 msgid "Starting file scan" 303 393 msgstr "ファイルのスキャンを開始" 304 394 305 #: includes/class-file-backup.php:56 395 #. translators: %d: number of files 396 #: includes/class-tnbu-file-backup.php 306 397 msgid "File scan completed: %d files" 307 398 msgstr "ファイルスキャンが完了: %d 件" 308 399 309 #: includes/class-file-backup.php:63 400 #. translators: 1: processed file count, 2: total files 401 #: includes/class-tnbu-file-backup.php 310 402 msgid "Compressing files: %1$d/%2$d" 311 403 msgstr "ファイルを圧縮中: %1$d/%2$d" 312 404 313 #: includes/class- file-backup.php:68405 #: includes/class-tnbu-file-backup.php 314 406 msgid "No files to add" 315 407 msgstr "追加するファイルがありません" 316 408 317 318 319 #: includes/class-file-backup.php:72 409 #: includes/class-tnbu-file-backup.php 320 410 msgid "Files compression completed" 321 411 msgstr "ファイル圧縮が完了しました" 322 412 323 #: includes/class-progress-manager.php:32 413 #: includes/class-tnbu-cron.php 414 msgid "Once Monthly" 415 msgstr "月1回" 416 417 #: includes/class-tnbu-progress-manager.php 324 418 msgid "Idle" 325 419 msgstr "待機中" 326 420 327 #: includes/class-utilities.php:156 421 #. translators: %s: directory path 422 #: includes/class-tnbu-utilities.php 328 423 msgid "Cannot write to backup directory: %s" 329 424 msgstr "バックアップディレクトリに書き込めません: %s" 330 331 #: includes/class-ajax-handler.php:345332 msgid "Selected files have been deleted."333 msgstr "選択したファイルを削除しました。"334 335 -
tiny-backup/trunk/languages/tiny-backup.pot
r3397190 r3487170 48 48 msgstr "" 49 49 50 #: includes/class-admin-interface.php:68 51 msgid "Select backup items" 52 msgstr "" 53 54 #: includes/class-admin-interface.php:68 55 msgid "only under wp-content" 50 #: includes/class-admin-interface.php:199 51 msgid "Choose what to backup from your uploads folder." 56 52 msgstr "" 57 53 -
tiny-backup/trunk/readme.txt
r3397693 r3487170 3 3 Tags: backup, database, files, zip, admin 4 4 Requires at least: 6.0 5 Tested up to: 6. 85 Tested up to: 6.9 6 6 Requires PHP: 7.4 7 Stable tag: 1. 1.17 Stable tag: 1.3.0 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html 10 10 11 Simple and minimal backup plugin for WordPress. Create database and files backups with one click.11 Simple and minimal backup plugin for WordPress. Create database and files backups manually or automatically on a schedule. 12 12 13 13 == Description == … … 16 16 You can create and download the bare minimum backup with just one click, stress-free. 17 17 18 - Database backup (SQL inside ZIP) 19 - Files backup (select folders under `wp-content`) 20 - Clear progress indicator and logs 18 **Manual Backup** 19 20 - Database backup (SQL inside ZIP) with a single click 21 - Files backup from your uploads folder — select specific subfolders as needed 22 - Clear progress indicator during backup 23 24 **Auto Backup (WP-Cron)** 25 26 - Set separate schedules for database and files backups (daily / weekly / monthly) 27 - Configure time, day of week, or day of month for each schedule 28 - Manage retention: set max generations for database and files independently 29 - Email notifications on success and/or failure (sent to the admin email address) 30 31 **General** 32 21 33 - No external services; everything runs on your server 34 - Backup files are stored in `wp-content/tiny-backup` 22 35 23 This plugin is ideal for small to medium sites that need quick on-demand backups.36 This plugin is ideal for small to medium sites that need simple, low-overhead backups. 24 37 25 38 == Installation == … … 28 41 2. Activate the plugin through the 'Plugins' screen in WordPress. 29 42 3. Go to Tools → Tiny Backup. 30 4. C hoose backup targets and click "Run backup now".43 4. Click "Database Backup" or "Files Backup" to run a manual backup, or configure Auto Backup settings. 31 44 32 45 == Frequently Asked Questions == … … 34 47 = Where are backups saved? = 35 48 36 B y default, backups are saved to `wp-content/tiny-backup`.49 Backups are saved to `wp-content/tiny-backup` by default. 37 50 38 51 = Can I change the destination directory? = … … 42 55 = Are scheduled backups supported? = 43 56 44 Not currently supported. This initial version only supports manual backups. Scheduled backups may be added in a future version. 57 Yes. As of version 1.3.0, you can configure automatic backups for database and files independently using WP-Cron. Options include daily, weekly, and monthly schedules. 58 59 = Does scheduled backup run at the exact time I set? = 60 61 WP-Cron is triggered by site visits, so the actual execution time may differ slightly from the configured time on low-traffic sites. The backup will run on the next page load after the scheduled time. 62 63 = What folders can I select for file backup? = 64 65 You can select the entire uploads folder or individual subfolders directly under it. Subfolders of subfolders are not selectable. 45 66 46 67 == Screenshots == 47 68 48 1. Settings screen - Choose what to backup: database and/or files, and select specific folders/plugins/themes under wp-content 49 2. Backup management screen - View all backup files with creation date and size, download or delete backups 69 1. Settings screen — Select backup items from the uploads folder 70 2. Auto Backup settings — Configure separate schedules, retention, and email notifications for database and files 71 3. Backup screen — Run manual backups and manage backup files 50 72 51 73 == Changelog == 52 74 53 = 1.1.1 = 75 = 1.3.0 = 76 77 - Added auto backup feature using WP-Cron (daily / weekly / monthly) 78 - Database and files can be scheduled independently 79 - Configurable retention (max generations) per backup type 80 - Email notifications on success and/or failure 81 - Split manual backup into separate "Database Backup" and "Files Backup" buttons 82 - Limited file backup scope to uploads folder (direct subfolders selectable) 83 - Introduced wp-scripts build pipeline for admin assets 84 85 = 1.2.0 = 86 87 - Internal improvements and refactoring. 88 89 = 1.1.1 = 54 90 55 91 - Bug fix. … … 59 95 - Added an action link to the plugin list for quick access to the settings page. 60 96 61 = 1.0.0 = 97 = 1.0.0 = 62 98 63 99 - Initial Release. … … 65 101 == Upgrade Notice == 66 102 67 = 1. 0.0 =103 = 1.3.0 = 68 104 69 - Initial release. 70 71 105 Auto backup, separate DB/files schedules, email notifications, and a redesigned backup UI are now available. -
tiny-backup/trunk/tiny-backup.php
r3397693 r3487170 3 3 Plugin Name: Tiny Backup 4 4 Description: Create database and files backups with minimal setup. 5 Version: 1. 1.16 Author: Takashi Fujisaki 5 Version: 1.3.0 6 Author: Takashi Fujisaki 7 7 Plugin URI: https://wordpress.org/plugins/tiny-backup/ 8 8 Author URI: https://yuiami.jp … … 11 11 Requires at least: 6.0 12 12 Requires PHP: 7.4 13 Tested up to: 6. 813 Tested up to: 6.9 14 14 License: GPLv2 or later 15 15 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 28 28 require_once plugin_dir_path( __FILE__ ) . 'includes/class-tnbu-ajax-handler.php'; 29 29 require_once plugin_dir_path( __FILE__ ) . 'includes/class-tnbu-core.php'; 30 require_once plugin_dir_path( __FILE__ ) . 'includes/class-tnbu-cron.php'; 30 31 31 32 32 33 // プラグイン初期化 33 34 TNBU_Core::init(); 35 TNBU_Cron::init(); 36 37 // カスタム cron スケジュール(monthly)を登録 38 add_filter( 'cron_schedules', array( 'TNBU_Cron', 'add_cron_schedules' ) ); 34 39 35 40 // 有効化フック(WPの定石としてメインファイルで登録) 36 41 register_activation_hook( __FILE__, array( 'TNBU_Core', 'on_activate' ) ); 42 43 // 無効化フック(cronスケジュール解除) 44 register_deactivation_hook( __FILE__, array( 'TNBU_Cron', 'unschedule_all' ) ); -
tiny-backup/trunk/uninstall.php
r3397693 r3487170 14 14 } 15 15 16 // 定数を利用するため コアクラスを読み込み16 // 定数を利用するためクラスを読み込み 17 17 require_once plugin_dir_path(__FILE__) . 'includes/class-tnbu-core.php'; 18 require_once plugin_dir_path(__FILE__) . 'includes/class-tnbu-cron.php'; 19 20 // cronスケジュールを解除 21 TNBU_Cron::unschedule_all(); 18 22 19 23 // プラグインの設定を削除
Note: See TracChangeset
for help on using the changeset viewer.