PluginProbe
Post Lockdown / 2.1
Post Lockdown v2.1
trunk 1.0.0 1.0.1 1.1 1.1.1 2.0 2.0.1 2.0.2 2.0.3 2.1 3.0 3.0.1 3.0.13 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 4.0 4.0.2 4.0.3 4.0.4 4.0.5 4.1.0 All 26 releases
post-lockdown / classes / class-postlockdown.php

class-postlockdown.php in Post Lockdown 2.1, at classes/class-postlockdown.php

300 lines 8.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Class PostLockdown
5 */
6 class PostLockdown {
7 /** Plugin key for options and the option page. */
8 const KEY = 'postlockdown';
9 const VERSION = '2.1';
10
11 /** @var array List of post IDs which cannot be edited, trashed or deleted. */
12 private $locked_post_ids = array();
13
14 /** @var array List of post IDs which cannot be trashed or deleted. */
15 private $protected_post_ids = array();
16
17 public $plugin_path;
18 public $plugin_url;
19 public $db_version;
20
21 public $registry = array();
22
23 public function __construct( $plugin_path, $plugin_url ) {
24 $this->plugin_path = $plugin_path;
25 $this->plugin_url = $plugin_url;
26
27 $this->load_registry();
28 $this->load_options();
29
30 add_action( 'delete_post', array( $this, '_update_option' ) );
31 add_filter( 'user_has_cap', array( $this, '_filter_cap' ), 10, 3 );
32 add_filter( 'wp_insert_post_data', array( $this, '_prevent_status_change' ), 10, 2 );
33 }
34
35 /**
36 * Returns an array of locked post IDs.
37 *
38 * @param bool $suppress_filters Whether to suppress filters and only return IDs
39 * selected on the Post Lockdown options page.
40 *
41 * @return array
42 */
43 public function get_locked_post_ids( $suppress_filters = false ) {
44 if ( $suppress_filters ) {
45 return $this->locked_post_ids;
46 }
47
48 return apply_filters( 'postlockdown_locked_posts', $this->locked_post_ids );
49 }
50
51 /**
52 * Returns an array of protected post IDs.
53 *
54 * @param bool $suppress_filters Whether to suppress filters and only return IDs
55 * selected on the Post Lockdown options page.
56 *
57 * @return array
58 */
59 public function get_protected_post_ids( $suppress_filters = false ) {
60 if ( $suppress_filters ) {
61 return $this->protected_post_ids;
62 }
63
64 return apply_filters( 'postlockdown_protected_posts', $this->protected_post_ids );
65 }
66
67 /**
68 * Returns whether there are any locked or protected posts set.
69 *
70 * @return bool
71 */
72 public function have_posts() {
73 return (bool) ( $this->get_locked_post_ids() || $this->get_protected_post_ids() );
74 }
75
76 /**
77 * Returns whether a post is locked.
78 *
79 * @param int $post_id The ID of the post to check.
80 * @param bool $suppress_filters
81 *
82 * @return bool
83 */
84 public function is_post_locked( $post_id, $suppress_filters = false ) {
85 if ( $suppress_filters ) {
86 return isset( $this->locked_post_ids[ $post_id ] );
87 }
88
89 $locked_post_ids = $this->get_locked_post_ids();
90
91 return isset( $locked_post_ids[ $post_id ] );
92 }
93
94 /**
95 * Returns whether a post is protected.
96 *
97 * @param int $post_id The ID of the post to check.
98 * @param bool $suppress_filters
99 *
100 * @return bool
101 */
102 public function is_post_protected( $post_id, $suppress_filters = false ) {
103 if ( $suppress_filters ) {
104 return isset( $this->protected_post_ids[ $post_id ] );
105 }
106
107 $protected_post_ids = $this->get_protected_post_ids();
108
109 return isset( $protected_post_ids[ $post_id ] );
110 }
111
112 /**
113 * @return array
114 */
115 public function get_post_types() {
116 $excluded_post_types = array();
117
118 if ( class_exists( 'WooCommerce' ) ) {
119 array_push( $excluded_post_types, 'shop_order', 'shop_coupon' );
120 }
121
122 $excluded_post_types = apply_filters( 'postlockdown_excluded_post_types', $excluded_post_types );
123
124 $post_types = get_post_types( array(
125 'show_ui' => true,
126 ) );
127
128 $post_types = array_diff( $post_types, $excluded_post_types );
129
130 return apply_filters( 'postlockdown_post_types', $post_types );
131 }
132
133 /**
134 * Returns the required capability a user must have to bypass all
135 * locked and protected post restrictions. Defaults to 'manage_options'.
136 *
137 * Also serves as a callback for the 'option_page_capability_{slug}' hook.
138 *
139 * @return string The required capability.
140 */
141 public function get_admin_cap() {
142 return apply_filters( 'postlockdown_admin_capability', 'manage_options' );
143 }
144
145 /**
146 * Filter for the 'user_has_cap' hook.
147 *
148 * Sets the capability to false when current_user_can() has been called on
149 * one of the capabilities we're interested in on a locked or protected post.
150 *
151 * @param array $allcaps All capabilities of the user.
152 * @param array $cap [0] Required capability.
153 * @param array $args [0] Requested capability.
154 * [1] User ID.
155 * [2] Post ID.
156 *
157 * @return array
158 */
159 public function _filter_cap( $allcaps, $cap, $args ) {
160 /* If there are no locked or protected posts, or the user
161 * has the required capability to bypass restrictions get out of here.
162 */
163 if ( ! $this->have_posts() || ! empty( $allcaps[ $this->get_admin_cap() ] ) ) {
164 return $allcaps;
165 }
166
167 $the_caps = apply_filters( 'postlockdown_capabilities', array(
168 'delete_post' => true,
169 'edit_post' => true,
170 ) );
171
172 // If it's not a capability we're interested in get out of here.
173 if ( ! isset( $the_caps[ $args[0] ] ) ) {
174 return $allcaps;
175 }
176
177 $post_id = $args[2];
178
179 if ( ! $post_id ) {
180 return $allcaps;
181 }
182
183 // If the post is locked set the capability to false.
184 $has_cap = ! $this->is_post_locked( $post_id );
185
186 /* If the user still has the capability and we're not editing a post,
187 * set the capability to false if the post is protected.
188 */
189 if ( $has_cap && 'edit_post' !== $args[0] ) {
190 $has_cap = ! $this->is_post_protected( $post_id );
191 }
192
193 $allcaps[ $cap[0] ] = $has_cap;
194
195 return $allcaps;
196 }
197
198 /**
199 * Filter for the 'wp_insert_post_data' hook.
200 *
201 * Reverts any changes made by a non-admin to a published protected post's status, privacy and password.
202 * Also reverts any date changes if they're set to a future date. If anything is changed a filter for
203 * the 'redirect_post_location' hook is added to display an admin notice letting the user know we reverted it.
204 *
205 * @param array $data Sanitized post data.
206 * @param array $postarr Raw post data. Contains post ID.
207 *
208 * @return array
209 */
210 public function _prevent_status_change( $data, $postarr ) {
211 $post_id = $postarr['ID'];
212 $post = get_post( $post_id );
213
214 /*
215 * Only continue if the current user is a non-admin
216 * and the post is both published and protected.
217 */
218 if ( current_user_can( $this->get_admin_cap() ) || 'publish' !== $post->post_status || ! $this->is_post_protected( $post_id ) ) {
219 return $data;
220 }
221
222 $changed = false;
223
224 if ( 'publish' !== $data['post_status'] ) {
225 $changed = true;
226 $data['post_status'] = $post->post_status;
227 }
228
229 if ( $data['post_password'] !== $post->post_password ) {
230 $changed = true;
231 $data['post_password'] = $post->post_password;
232 }
233
234 // Revert the post date if it's set to a future date.
235 if ( $data['post_date'] !== $post->post_date && strtotime( $data['post_date'] ) > time() ) {
236 $changed = true;
237 $data['post_date'] = $post->post_date;
238 $data['post_date_gmt'] = $post->post_date_gmt;
239 }
240
241 if ( $changed ) {
242 add_filter( 'redirect_post_location', array( $this->registry['AdminNotice'], '_add_query_arg' ) );
243 }
244
245 return $data;
246 }
247
248 /**
249 * Callback for the 'delete_post' hook.
250 *
251 * Removes the deleted post's ID from both locked and protected arrays.
252 *
253 * @param int $post_id Deleted post's ID.
254 */
255 public function _update_option( $post_id ) {
256 unset( $this->locked_post_ids[ $post_id ], $this->protected_post_ids[ $post_id ] );
257
258 update_option( self::KEY, array(
259 'locked_post_ids' => $this->locked_post_ids,
260 'protected_post_ids' => $this->protected_post_ids,
261 ) );
262 }
263
264 /**
265 * Callback for register_uninstall_hook() function.
266 *
267 * Removes the plugin option from the database when it is uninstalled.
268 */
269 public static function _uninstall() {
270 delete_option( self::KEY );
271 }
272
273 /**
274 * Initialises class instances and adds them to our registry array.
275 */
276 private function load_registry() {
277 $this->registry = array(
278 'AdminNotice' => new PostLockdown_AdminNotice( $this->plugin_path ),
279 'OptionsPage' => new PostLockdown_OptionsPage( $this ),
280 'StatusColumn' => new PostLockdown_StatusColumn( $this ),
281 );
282 }
283
284 /**
285 * Sets the arrays of locked and protected post IDs.
286 *
287 */
288 private function load_options() {
289 $options = get_option( self::KEY, array() );
290
291 if ( ! empty( $options['locked_post_ids'] ) && is_array( $options['locked_post_ids'] ) ) {
292 $this->locked_post_ids = $options['locked_post_ids'];
293 }
294
295 if ( ! empty( $options['protected_post_ids'] ) && is_array( $options['protected_post_ids'] ) ) {
296 $this->protected_post_ids = $options['protected_post_ids'];
297 }
298 }
299 }
300