Skip to content

Commit 8d23aca

Browse files
committed
initial commit
1 parent 91392f9 commit 8d23aca

16 files changed

+1185
-1
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.DS_Store
2+
composer.lock
3+
node_modules/
4+
vendor/
5+
.idea

README.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,32 @@
1-
# beapi-posts-lifetime
1+
Posts Lifetime
2+
=======================
3+
4+
Define a lifetime for contents (posts and CPTs).
5+
Contents will be placed in trash after expiration. And permanently deleted after a defined retention period.
6+
Expirated posts can be followed on a dashboard widget.
7+
Post authors are informated when content is placed in trash.
8+
9+
## Installation
10+
11+
3 possibilities.
12+
13+
* Take the ZIP archive proposed in the Github releases
14+
* Add "beapi/beapi-posts-lifetime" on composer json project file
15+
* Take this GIT repository and call "composer install" command
16+
17+
## Compatibility
18+
19+
Compatible up to WordPress 6.x
20+
21+
## Who ?
22+
23+
Created by [Be API](https://beapi.fr), the French WordPress leader agency since 2009. Based in Paris, we are more than 30 people and always [hiring](https://beapi.workable.com) some fun and talented guys. So we will be pleased to work with you.
24+
25+
This plugin is only maintained, which means we do not guarantee some free support. Consider reporting an [issue](#issues--features-request--proposal) and be patient.
26+
27+
If you really like what we do or want to thank us for our quick work, feel free to [donate](https://www.paypal.me/BeAPI) as much as you want / can, even 1€ is a great gift for buying coffee :)
28+
29+
## Changelog
30+
31+
### 1.0.0
32+
* First release

classes/Admin.php

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
<?php
2+
3+
namespace Beapi\PostsLifetime;
4+
5+
use WP_Post;
6+
7+
class Admin {
8+
protected function init(): void {
9+
add_action( 'wp_dashboard_setup', [ $this, 'register_dashboard_widget' ] );
10+
add_action( 'admin_init', [ $this, 'trash_retention_period' ] );
11+
add_action( 'add_meta_boxes', [ $this, 'add_post_lifetime_metabox' ] );
12+
add_action( 'save_post', [ $this, 'save_post_lifetime_metabox' ] );
13+
}
14+
15+
/**
16+
* Use the trait
17+
*/
18+
use Singleton;
19+
20+
/**
21+
* Register the widget on dashboard
22+
*
23+
* @return void
24+
*/
25+
public function register_dashboard_widget(): void {
26+
wp_add_dashboard_widget(
27+
'beapi_posts_lifetime_widget',
28+
__( 'Posts Lifetime Info', 'posts_lifetime' ),
29+
[ $this, 'render_dashboard_widget' ]
30+
);
31+
}
32+
33+
/**
34+
* Render the widget content
35+
*
36+
* @return void
37+
*/
38+
public function render_dashboard_widget(): void {
39+
$expired_posts = Helpers::get_trashed_posts_with_lifetime();
40+
$retention_period = get_option( 'trash_retention_period', 30 ); // 30 days default if not set
41+
?>
42+
<div>
43+
<h4><?php esc_html_e( 'Expired posts', 'posts_lifetime' ); ?></h4>
44+
<p>
45+
<?php
46+
printf(
47+
esc_html__( 'Here are the last 10 expired posts, to be deleted within %d days after being in trash', 'posts_lifetime' ),
48+
$retention_period
49+
);
50+
?>
51+
</p>
52+
<ul>
53+
<?php if ( ! empty( $expired_posts ) ) : ?>
54+
<?php foreach ( $expired_posts as $post ) :
55+
$trash_time = get_post_meta( $post->ID, '_wp_trash_meta_time', true );
56+
?>
57+
<li>
58+
<a href="<?php echo esc_url( get_edit_post_link( $post->ID ) ); ?>" target="_blank">
59+
<?php echo esc_html( get_the_title( $post->ID ) ); ?>
60+
</a>
61+
<span><?php
62+
if ( ! empty( $trash_time ) ) {
63+
// Convert timestamp in readable date
64+
$trash_date = date( 'd-m-Y H:i:s', $trash_time );
65+
echo 'In trash since : ' . esc_html( $trash_date );
66+
} else {
67+
echo 'This post has not been moved to trash.';
68+
} ?></span>
69+
</li>
70+
<?php endforeach; ?>
71+
<?php else : ?>
72+
<li><?php esc_html_e( 'No expired posts.', 'posts_lifetime' ); ?></li>
73+
<?php endif; ?>
74+
</ul>
75+
</div>
76+
<?php
77+
}
78+
79+
/**
80+
* Add metabox to define "pl_post_lifetime" post meta
81+
*
82+
* @return void
83+
*/
84+
public function add_post_lifetime_metabox(): void {
85+
add_meta_box(
86+
'pl_post_lifetime_metabox',
87+
__( 'Post Lifetime', 'posts_lifetime' ),
88+
[ $this, 'render_post_lifetime_metabox' ],
89+
);
90+
}
91+
92+
/**
93+
* Display metabox content
94+
*
95+
* @param WP_Post $post
96+
*
97+
* @return void
98+
*/
99+
public function render_post_lifetime_metabox( WP_Post $post ): void {
100+
$post_lifetime = Helpers::get_post_lifetime( $post->ID );
101+
wp_nonce_field( 'save_pl_post_lifetime', 'pl_post_lifetime_nonce' );
102+
?>
103+
<p>
104+
<label for="pl_post_lifetime">
105+
<?php _e( 'Define the post expiration date:', 'posts_lifetime' ); ?>
106+
</label>
107+
</p>
108+
<p>
109+
<input
110+
type="date"
111+
name="pl_post_lifetime"
112+
id="pl_post_lifetime"
113+
value="<?php echo esc_attr( $post_lifetime ); ?>"
114+
class="widefat"
115+
/>
116+
</p>
117+
<?php
118+
}
119+
120+
/**
121+
* Save "pl_post_lifetime" post meta on save_post.
122+
*
123+
* @param int $post_id
124+
*
125+
* @return void
126+
*/
127+
public function save_post_lifetime_metabox( int $post_id ): void {
128+
if ( ! current_user_can( 'edit_post', $post_id ) ) {
129+
return;
130+
}
131+
132+
// Check the nonce
133+
if ( ! isset( $_POST['pl_post_lifetime_nonce'] ) || ! wp_verify_nonce( $_POST['pl_post_lifetime_nonce'], 'save_pl_post_lifetime' ) ) {
134+
return;
135+
}
136+
137+
$raw_date = sanitize_text_field( $_POST['pl_post_lifetime'] );
138+
139+
$formatted_date = Helpers::format_date( $raw_date, 'Y-m-d', 'Y-m-d' );
140+
141+
if ( ! empty( $formatted_date ) ) {
142+
Helpers::set_post_lifetime( $post_id, $formatted_date );
143+
} else {
144+
delete_post_meta( $post_id, 'pl_post_lifetime' );
145+
}
146+
}
147+
148+
/**
149+
* Register an option for the trash retention period in the WordPress settings.
150+
*
151+
* @return void
152+
*/
153+
public function trash_retention_period(): void {
154+
register_setting( 'general', 'trash_retention_period', [
155+
'type' => 'integer',
156+
'sanitize_callback' => 'absint',
157+
'default' => 30, // 30 jours par défaut
158+
] );
159+
160+
add_settings_field(
161+
'trash_retention_period',
162+
__( 'Trash retention period (days) for posts', 'posts_lifetime' ),
163+
function () {
164+
$value = get_option( 'trash_retention_period', 30 );
165+
echo '<input type="number" name="trash_retention_period" value="' . esc_attr( $value ) . '" class="small-text" min="1">';
166+
},
167+
'general',
168+
'default'
169+
);
170+
}
171+
}

classes/Cron/Cron.php

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?php
2+
3+
namespace Beapi\PostsLifetime\Cron;
4+
5+
/**
6+
* This class needs Bea_Log to work
7+
* This class purpose is to handle cron process by :
8+
* - creating lock files
9+
* - Having a start and an end process methods
10+
*
11+
* Class Cron
12+
* @package Beapi\PostsLifetime
13+
*/
14+
abstract class Cron {
15+
16+
/**
17+
* Type for the log filename
18+
*
19+
* @var string
20+
*/
21+
protected $type = '';
22+
23+
/**
24+
* @var \Bea_Log $log
25+
*/
26+
private $log;
27+
28+
/**
29+
* @var \WP_Filesystem_Direct $filesystem
30+
*/
31+
protected $filesystem;
32+
33+
/**
34+
* Lock option name
35+
*
36+
* @var string
37+
*/
38+
private $lock_option;
39+
40+
/**
41+
* Process the cron
42+
*
43+
* @return mixed
44+
*/
45+
abstract public function process();
46+
47+
/**
48+
* Check if lock exist
49+
*
50+
* @return bool
51+
*/
52+
public function is_locked() {
53+
$lock = get_option( $this->lock_option, false );
54+
55+
// Check if lock exists and is not expired
56+
return $lock && $lock > time();
57+
}
58+
59+
/**
60+
* Create the lock with expiration time
61+
*
62+
* @param int $duration Duration of the lock in seconds (default: 5 minutes).
63+
* @return bool
64+
*/
65+
public function create_lock( $duration = 300 ) {
66+
$this->lock_option = 'cron_lock_' . sanitize_key( $this->type );
67+
68+
if ( $this->is_locked() ) {
69+
return false; // Already locked
70+
}
71+
72+
// Set lock with expiration time
73+
return update_option( $this->lock_option, time() + $duration, false );
74+
}
75+
76+
/**
77+
* Delete the lock
78+
*
79+
* @return bool
80+
*/
81+
public function delete_lock() {
82+
// Delete the lock from the database
83+
return delete_option( $this->lock_option );
84+
}
85+
}

0 commit comments

Comments
 (0)