@@ -37,7 +37,7 @@ class List_Table extends WP_List_Table {
3737 *
3838 * @var array<string>
3939 */
40- public array $ statuses = [ 'all ' , 'active ' , 'inactive ' , 'recently_activated ' ];
40+ public array $ statuses = [ 'all ' , 'active ' , 'inactive ' , 'recently_activated ' , ' trashed ' ];
4141
4242 /**
4343 * Column name to use when ordering the snippets list.
@@ -246,7 +246,26 @@ public function get_action_link( string $action, Snippet $snippet ): string {
246246 private function get_snippet_action_links ( Snippet $ snippet ): array {
247247 $ actions = array ();
248248
249- if ( ! $ this ->is_network && $ snippet ->network && ! $ snippet ->shared_network ) {
249+ if ( $ snippet ->is_trashed () ) {
250+ $ actions ['restore ' ] = sprintf (
251+ '<a href="%s">%s</a> ' ,
252+ esc_url ( $ this ->get_action_link ( 'restore ' , $ snippet ) ),
253+ esc_html__ ( 'Restore ' , 'code-snippets ' )
254+ );
255+
256+ $ actions ['delete_permanently ' ] = sprintf (
257+ '<a href="%2$s" class="delete" onclick="%3$s">%1$s</a> ' ,
258+ esc_html__ ( 'Delete Permanently ' , 'code-snippets ' ),
259+ esc_url ( $ this ->get_action_link ( 'delete_permanently ' , $ snippet ) ),
260+ esc_js (
261+ sprintf (
262+ 'return confirm("%s"); ' ,
263+ esc_html__ ( 'You are about to permanently delete the selected item. ' , 'code-snippets ' ) . "\n" .
264+ esc_html__ ( "'Cancel' to stop, 'OK' to delete. " , 'code-snippets ' )
265+ )
266+ )
267+ );
268+ } elseif ( ! $ this ->is_network && $ snippet ->network && ! $ snippet ->shared_network ) {
250269 // Display special links if on a subsite and dealing with a network-active snippet.
251270 if ( $ snippet ->active ) {
252271 $ actions ['network_active ' ] = esc_html__ ( 'Network Active ' , 'code-snippets ' );
@@ -267,16 +286,9 @@ private function get_snippet_action_links( Snippet $snippet ): array {
267286 }
268287
269288 $ actions ['delete ' ] = sprintf (
270- '<a href="%2$s" class="delete" onclick="%3$s">%1$s</a> ' ,
271- esc_html__ ( 'Delete ' , 'code-snippets ' ),
272- esc_url ( $ this ->get_action_link ( 'delete ' , $ snippet ) ),
273- esc_js (
274- sprintf (
275- 'return confirm("%s"); ' ,
276- esc_html__ ( 'You are about to permanently delete the selected item. ' , 'code-snippets ' ) . "\n" .
277- esc_html__ ( "'Cancel' to stop, 'OK' to delete. " , 'code-snippets ' )
278- )
279- )
289+ '<a href="%2$s" class="delete">%1$s</a> ' ,
290+ esc_html__ ( 'Trash ' , 'code-snippets ' ),
291+ esc_url ( $ this ->get_action_link ( 'delete ' , $ snippet ) )
280292 );
281293 }
282294
@@ -291,6 +303,10 @@ private function get_snippet_action_links( Snippet $snippet ): array {
291303 * @return string Output for activation switch.
292304 */
293305 protected function column_activate ( Snippet $ snippet ): string {
306+ if ( $ snippet ->is_trashed () ) {
307+ return '' ;
308+ }
309+
294310 if ( $ this ->is_network && ( $ snippet ->shared_network || ( ! $ this ->is_network && $ snippet ->network && ! $ snippet ->shared_network ) ) ) {
295311 return '' ;
296312 }
@@ -352,8 +368,8 @@ protected function column_name( Snippet $snippet ): string {
352368
353369 $ out = esc_html ( $ snippet ->display_name );
354370
355- // Add a link to the snippet if it isn't an unreadable network-only snippet.
356- if ( $ this ->is_network || ! $ snippet ->network || current_user_can ( code_snippets ()->get_network_cap_name () ) ) {
371+ // Add a link to the snippet if it isn't an unreadable network-only snippet and isn't trashed .
372+ if ( ! $ snippet -> is_trashed () && ( $ this ->is_network || ! $ snippet ->network || current_user_can ( code_snippets ()->get_network_cap_name () ) ) ) {
357373 $ out = sprintf (
358374 '<a href="%s" class="snippet-name">%s</a> ' ,
359375 esc_attr ( code_snippets ()->get_snippet_edit_url ( $ snippet ->id , $ snippet ->network ? 'network ' : 'admin ' ) ),
@@ -482,14 +498,23 @@ public function get_sortable_columns(): array {
482498 * @return array<string, string> An array of menu items with the ID paired to the label
483499 */
484500 public function get_bulk_actions (): array {
485- $ actions = [
486- 'activate-selected ' => $ this ->is_network ? __ ( 'Network Activate ' , 'code-snippets ' ) : __ ( 'Activate ' , 'code-snippets ' ),
487- 'deactivate-selected ' => $ this ->is_network ? __ ( 'Network Deactivate ' , 'code-snippets ' ) : __ ( 'Deactivate ' , 'code-snippets ' ),
488- 'clone-selected ' => __ ( 'Clone ' , 'code-snippets ' ),
489- 'download-selected ' => __ ( 'Export Code ' , 'code-snippets ' ),
490- 'export-selected ' => __ ( 'Export ' , 'code-snippets ' ),
491- 'delete-selected ' => __ ( 'Delete ' , 'code-snippets ' ),
492- ];
501+ global $ status ;
502+
503+ if ( 'trashed ' === $ status ) {
504+ $ actions = [
505+ 'restore-selected ' => __ ( 'Restore ' , 'code-snippets ' ),
506+ 'delete-permanently-selected ' => __ ( 'Delete Permanently ' , 'code-snippets ' ),
507+ ];
508+ } else {
509+ $ actions = [
510+ 'activate-selected ' => $ this ->is_network ? __ ( 'Network Activate ' , 'code-snippets ' ) : __ ( 'Activate ' , 'code-snippets ' ),
511+ 'deactivate-selected ' => $ this ->is_network ? __ ( 'Network Deactivate ' , 'code-snippets ' ) : __ ( 'Deactivate ' , 'code-snippets ' ),
512+ 'clone-selected ' => __ ( 'Clone ' , 'code-snippets ' ),
513+ 'download-selected ' => __ ( 'Export Code ' , 'code-snippets ' ),
514+ 'export-selected ' => __ ( 'Export ' , 'code-snippets ' ),
515+ 'delete-selected ' => __ ( 'Move to Trash ' , 'code-snippets ' ),
516+ ];
517+ }
493518
494519 return apply_filters ( 'code_snippets/list_table/bulk_actions ' , $ actions );
495520 }
@@ -558,6 +583,14 @@ public function get_views(): array {
558583 'code-snippets '
559584 );
560585
586+ // translators: %s: total number of trashed snippets.
587+ $ labels ['trashed ' ] = _n (
588+ 'Trashed <span class="count">(%s)</span> ' ,
589+ 'Trashed <span class="count">(%s)</span> ' ,
590+ $ count ,
591+ 'code-snippets '
592+ );
593+
561594 // The page URL with the status parameter.
562595 $ url = esc_url ( add_query_arg ( 'status ' , $ type ) );
563596
@@ -737,9 +770,17 @@ private function perform_action( int $id, string $action ) {
737770 return 'cloned ' ;
738771
739772 case 'delete ' :
740- delete_snippet ( $ id , $ this ->is_network );
773+ trash_snippet ( $ id , $ this ->is_network );
741774 return 'deleted ' ;
742775
776+ case 'restore ' :
777+ restore_snippet ( $ id , $ this ->is_network );
778+ return 'restored ' ;
779+
780+ case 'delete_permanently ' :
781+ delete_snippet ( $ id , $ this ->is_network );
782+ return 'deleted_permanently ' ;
783+
743784 case 'export ' :
744785 $ export = new Export_Attachment ( [ $ id ], $ this ->is_network );
745786 $ export ->download_snippets_json ();
@@ -789,7 +830,28 @@ public function process_requested_actions() {
789830 $ result = $ this ->perform_action ( $ id , sanitize_key ( $ _GET ['action ' ] ) );
790831
791832 if ( $ result ) {
792- wp_safe_redirect ( esc_url_raw ( add_query_arg ( 'result ' , $ result ) ) );
833+ $ redirect_args = array ( 'result ' => $ result );
834+
835+ if ( 'deleted ' === $ result ) {
836+ $ redirect_args ['ids ' ] = $ id ;
837+ }
838+
839+ wp_safe_redirect ( esc_url_raw ( add_query_arg ( $ redirect_args ) ) );
840+ exit ;
841+ }
842+ }
843+
844+ if ( isset ( $ _GET ['action ' ] ) && 'restore ' === $ _GET ['action ' ] && isset ( $ _GET ['ids ' ] ) ) {
845+ $ ids = array_map ( 'intval ' , explode ( ', ' , sanitize_text_field ( $ _GET ['ids ' ] ) ) );
846+
847+ if ( ! empty ( $ ids ) ) {
848+ check_admin_referer ( 'bulk- ' . $ this ->_args ['plural ' ] );
849+
850+ foreach ( $ ids as $ id ) {
851+ restore_snippet ( $ id , $ this ->is_network );
852+ }
853+
854+ wp_safe_redirect ( esc_url_raw ( add_query_arg ( 'result ' , 'restored ' ) ) );
793855 exit ;
794856 }
795857 }
@@ -860,14 +922,35 @@ public function process_requested_actions() {
860922
861923 case 'delete-selected ' :
862924 foreach ( $ ids as $ id ) {
863- delete_snippet ( $ id , $ this ->is_network );
925+ trash_snippet ( $ id , $ this ->is_network );
864926 }
865927 $ result = 'deleted-multi ' ;
866928 break ;
929+
930+ case 'restore-selected ' :
931+ foreach ( $ ids as $ id ) {
932+ restore_snippet ( $ id , $ this ->is_network );
933+ }
934+ $ result = 'restored-multi ' ;
935+ break ;
936+
937+ case 'delete-permanently-selected ' :
938+ foreach ( $ ids as $ id ) {
939+ delete_snippet ( $ id , $ this ->is_network );
940+ }
941+ $ result = 'deleted-permanently-multi ' ;
942+ break ;
867943 }
868944
869945 if ( isset ( $ result ) ) {
870- wp_safe_redirect ( esc_url_raw ( add_query_arg ( 'result ' , $ result ) ) );
946+ $ redirect_args = array ( 'result ' => $ result );
947+
948+ // Add snippet IDs for undo functionality on bulk delete
949+ if ( 'deleted-multi ' === $ result && ! empty ( $ ids ) ) {
950+ $ redirect_args ['ids ' ] = implode ( ', ' , $ ids );
951+ }
952+
953+ wp_safe_redirect ( esc_url_raw ( add_query_arg ( $ redirect_args ) ) );
871954 exit ;
872955 }
873956 }
@@ -978,9 +1061,19 @@ public function prepare_items() {
9781061 $ this ->process_requested_actions ();
9791062 $ snippets = array_fill_keys ( $ this ->statuses , array () );
9801063
981- $ snippets [ ' all ' ] = apply_filters ( 'code_snippets/list_table/get_snippets ' , get_snippets () );
1064+ $ all_snippets = apply_filters ( 'code_snippets/list_table/get_snippets ' , get_snippets () );
9821065 $ this ->fetch_shared_network_snippets ();
9831066
1067+ // Separate trashed snippets from the main collection
1068+ $ snippets ['trashed ' ] = array_filter ( $ all_snippets , function ( $ snippet ) {
1069+ return $ snippet ->is_trashed ();
1070+ });
1071+
1072+ // Filter out trashed snippets from the 'all' collection
1073+ $ snippets ['all ' ] = array_filter ( $ all_snippets , function ( $ snippet ) {
1074+ return ! $ snippet ->is_trashed ();
1075+ });
1076+
9841077 foreach ( $ snippets ['all ' ] as $ snippet ) {
9851078 if ( $ snippet ->active ) {
9861079 $ this ->active_by_condition [ $ snippet ->condition_id ][] = $ snippet ;
@@ -997,23 +1090,39 @@ function ( Snippet $snippet ) use ( $type ) {
9971090 return $ type === $ snippet ->type ;
9981091 }
9991092 );
1093+
1094+ // Filter trashed snippets by type
1095+ $ snippets ['trashed ' ] = array_filter (
1096+ $ snippets ['trashed ' ],
1097+ function ( Snippet $ snippet ) use ( $ type ) {
1098+ return $ type === $ snippet ->type ;
1099+ }
1100+ );
10001101 }
10011102
1002- // Add scope tags.
1103+ // Add scope tags to all snippets (including trashed) .
10031104 foreach ( $ snippets ['all ' ] as $ snippet ) {
10041105 if ( 'global ' !== $ snippet ->scope ) {
10051106 $ snippet ->add_tag ( $ snippet ->scope );
10061107 }
10071108 }
1109+
1110+ foreach ( $ snippets ['trashed ' ] as $ snippet ) {
1111+ if ( 'global ' !== $ snippet ->scope ) {
1112+ $ snippet ->add_tag ( $ snippet ->scope );
1113+ }
1114+ }
10081115
10091116 // Filter snippets by tag.
10101117 if ( ! empty ( $ _GET ['tag ' ] ) ) {
10111118 $ snippets ['all ' ] = array_filter ( $ snippets ['all ' ], array ( $ this , 'tags_filter_callback ' ) );
1119+ $ snippets ['trashed ' ] = array_filter ( $ snippets ['trashed ' ], array ( $ this , 'tags_filter_callback ' ) );
10121120 }
10131121
10141122 // Filter snippets based on search query.
10151123 if ( $ s ) {
10161124 $ snippets ['all ' ] = array_filter ( $ snippets ['all ' ], array ( $ this , 'search_by_line_callback ' ) );
1125+ $ snippets ['trashed ' ] = array_filter ( $ snippets ['trashed ' ], array ( $ this , 'search_by_line_callback ' ) );
10171126 }
10181127
10191128 // Clear recently activated snippets older than a week.
@@ -1037,6 +1146,11 @@ function ( Snippet $snippet ) use ( $type ) {
10371146 * @var Snippet $snippet
10381147 */
10391148 foreach ( $ snippets ['all ' ] as $ snippet ) {
1149+ // Skip trashed snippets (they're already in their own section)
1150+ if ( $ snippet ->is_trashed () ) {
1151+ continue ;
1152+ }
1153+
10401154 if ( $ snippet ->active || $ this ->is_condition_active ( $ snippet ) ) {
10411155 $ snippets ['active ' ][] = $ snippet ;
10421156 } else {
@@ -1310,7 +1424,6 @@ public function search_notice() {
13101424 */
13111425 public function single_row ( $ item ) {
13121426 $ status = $ item ->active || $ this ->is_condition_active ( $ item ) ? 'active ' : 'inactive ' ;
1313-
13141427 $ row_class = "snippet $ status-snippet $ item ->type -snippet $ item ->scope -scope " ;
13151428
13161429 if ( $ item ->shared_network ) {
0 commit comments