Admin
2 weeks ago
Ajax
2 weeks ago
Asset
2 weeks ago
Context
2 weeks ago
Customizer
2 weeks ago
Debug_Bar
2 weeks ago
Dialog
2 weeks ago
Documentation
2 weeks ago
Duplicate
2 weeks ago
Editor
2 weeks ago
Image
2 weeks ago
JSON_LD
2 weeks ago
Languages
2 weeks ago
Log
2 weeks ago
Meta
2 weeks ago
Models
2 weeks ago
PUE
2 weeks ago
Process
2 weeks ago
Promoter
2 weeks ago
REST
2 weeks ago
Repository
2 weeks ago
Service_Providers
2 weeks ago
Shortcode
2 weeks ago
Support
2 weeks ago
Tabbed_View
2 weeks ago
Tooltip
2 weeks ago
Traits
2 weeks ago
Utils
2 weeks ago
Validator
2 weeks ago
Widget
2 weeks ago
Abstract_Deactivation.php
2 weeks ago
Abstract_Plugin_Register.php
2 weeks ago
App_Shop.php
2 weeks ago
Assets.php
2 weeks ago
Assets_Pipeline.php
2 weeks ago
Autoloader.php
2 weeks ago
Cache.php
2 weeks ago
Cache_Listener.php
2 weeks ago
Changelog_Reader.php
2 weeks ago
Container.php
2 weeks ago
Context.php
2 weeks ago
Cost_Utils.php
2 weeks ago
Credits.php
2 weeks ago
Customizer.php
2 weeks ago
DB_Lock.php
2 weeks ago
Data.php
2 weeks ago
Date_Utils.php
2 weeks ago
Db.php
2 weeks ago
Debug.php
2 weeks ago
Dependency.php
2 weeks ago
Deprecation.php
2 weeks ago
Editor.php
2 weeks ago
Error.php
2 weeks ago
Exception.php
2 weeks ago
Extension.php
2 weeks ago
Extension_Loader.php
2 weeks ago
Feature_Detection.php
2 weeks ago
Field.php
2 weeks ago
Field_Conditional.php
2 weeks ago
Freemius.php
2 weeks ago
Log.php
2 weeks ago
Main.php
2 weeks ago
Notices.php
2 weeks ago
Plugin_Meta_Links.php
2 weeks ago
Plugins.php
2 weeks ago
Plugins_API.php
2 weeks ago
Post_History.php
2 weeks ago
Post_Transient.php
2 weeks ago
Promise.php
2 weeks ago
Repository.php
2 weeks ago
Rewrite.php
2 weeks ago
Settings.php
2 weeks ago
Settings_Manager.php
2 weeks ago
Settings_Tab.php
2 weeks ago
Simple_Table.php
2 weeks ago
Support.php
2 weeks ago
Tabbed_View.php
2 weeks ago
Template.php
2 weeks ago
Template_Factory.php
2 weeks ago
Template_Part_Cache.php
2 weeks ago
Templates.php
2 weeks ago
Terms.php
2 weeks ago
Timezones.php
2 weeks ago
Tracker.php
2 weeks ago
Updater.php
2 weeks ago
Validate.php
2 weeks ago
View_Helpers.php
2 weeks ago
Tracker.php
468 lines
| 1 | <?php |
| 2 | |
| 3 | /** |
| 4 | * Class Tribe__Tracker |
| 5 | * |
| 6 | * Tracks changes of post attributes. |
| 7 | */ |
| 8 | class Tribe__Tracker { |
| 9 | /** |
| 10 | * @var string The meta field used to track changes. |
| 11 | */ |
| 12 | public static $field_key = '_tribe_modified_fields'; |
| 13 | |
| 14 | /** |
| 15 | * @var bool Whether the class is tracking terms or not. |
| 16 | */ |
| 17 | protected $track_terms = true; |
| 18 | |
| 19 | /** |
| 20 | * @var array An array of the tracked post types. |
| 21 | */ |
| 22 | protected $tracked_post_types = []; |
| 23 | |
| 24 | /** |
| 25 | * @var array An array of the tracked taxonomies. |
| 26 | */ |
| 27 | protected $tracked_taxonomies = []; |
| 28 | |
| 29 | /** |
| 30 | * Hooks up the methods that will actually track the fields we are looking for. |
| 31 | */ |
| 32 | public function hook() { |
| 33 | // Track the Meta Updates for Meta That came from the correct Post Types |
| 34 | add_filter( 'update_post_metadata', [ $this, 'filter_watch_updated_meta' ], PHP_INT_MAX - 1, 5 ); |
| 35 | |
| 36 | // After a meta is added we mark that is has been modified |
| 37 | add_action( 'added_post_meta', [ $this, 'register_added_deleted_meta' ], PHP_INT_MAX - 1, 3 ); |
| 38 | |
| 39 | // Before a meta is removed we mark that is has been modified |
| 40 | add_action( 'delete_post_meta', [ $this, 'register_added_deleted_meta' ], PHP_INT_MAX - 1, 3 ); |
| 41 | |
| 42 | // Track the Post Fields Updates for Meta in the correct Post Types |
| 43 | add_action( 'post_updated', [ $this, 'filter_watch_post_fields' ], 10, 3 ); |
| 44 | |
| 45 | // Track the Post term updates |
| 46 | add_action( 'set_object_terms', [ $this, 'track_taxonomy_term_changes' ], 10, 6 ); |
| 47 | |
| 48 | // Clean up modified fields if the post is removed. |
| 49 | add_action( 'delete_post', [ $this, 'cleanup_meta_fields' ] ); |
| 50 | } |
| 51 | |
| 52 | /** |
| 53 | * Determines if a post value has been changed |
| 54 | * |
| 55 | * @param string $field Field to compare against |
| 56 | * @param array $new New data |
| 57 | * @param array $old WP_Post pre-update |
| 58 | * |
| 59 | * @return boolean |
| 60 | */ |
| 61 | public function has_field_changed( $field, $new, $old ) { |
| 62 | if ( ! is_object( $new ) ) { |
| 63 | $new = (object) $new; |
| 64 | } |
| 65 | |
| 66 | if ( ! is_object( $old ) ) { |
| 67 | $old = (object) $old; |
| 68 | } |
| 69 | |
| 70 | if ( ! isset( $new->$field ) ) { |
| 71 | return false; |
| 72 | } |
| 73 | |
| 74 | if ( isset( $new->$field ) && ! isset( $old->$field ) ) { |
| 75 | return true; |
| 76 | } |
| 77 | |
| 78 | if ( $new->$field !== $old->$field ) { |
| 79 | return true; |
| 80 | } |
| 81 | |
| 82 | return false; |
| 83 | } |
| 84 | |
| 85 | /** |
| 86 | * Get the date(timestamp) of last modification for a tracked field. |
| 87 | * |
| 88 | * @since 4.12.3 |
| 89 | * |
| 90 | * @param string $meta_key The key for the meta field we're interested in. |
| 91 | * @param int $post_id The ID of the post to check. |
| 92 | * |
| 93 | * @return boolean|string The change timestamp or false if the field is not found/empty. |
| 94 | */ |
| 95 | public function get_modified_date( $meta_key, $post_id ) { |
| 96 | $modified = get_post_meta( $post_id, self::$field_key, true ); |
| 97 | |
| 98 | // If the key is missing or empty/null return false - no recorded change. |
| 99 | return Tribe__Utils__Array::get( $modified, $meta_key, false ); |
| 100 | } |
| 101 | |
| 102 | /** |
| 103 | * Easy way to see currently which post types are being tracked by our code. |
| 104 | * |
| 105 | * @return array |
| 106 | */ |
| 107 | public function get_post_types() { |
| 108 | // By default we are not tracking anything |
| 109 | $tracked_post_types = []; |
| 110 | |
| 111 | /** |
| 112 | * Adds a way for Developers to add and remove which post types will be tracked |
| 113 | * |
| 114 | * Note: Removing any of the default methods will affect how we deal with fields |
| 115 | * affected by the authority settings defined on this installation |
| 116 | * |
| 117 | * @var array |
| 118 | */ |
| 119 | $tracked_post_types = (array) apply_filters( 'tribe_tracker_post_types', $this->tracked_post_types ); |
| 120 | |
| 121 | return $tracked_post_types; |
| 122 | } |
| 123 | |
| 124 | /** |
| 125 | * Easy way to see currenlty which meta values are been tracked by our code |
| 126 | * |
| 127 | * @return array |
| 128 | */ |
| 129 | public function get_excluded_meta_keys() { |
| 130 | // By default we are not tracking anything |
| 131 | $excluded_keys = [ |
| 132 | '_edit_lock', |
| 133 | self::$field_key, |
| 134 | ]; |
| 135 | |
| 136 | /** |
| 137 | * Adds a way for Developers remove Meta Keys that shouldn't be tracked |
| 138 | * |
| 139 | * Note: Removing any of the default methods will affect how we deal with fields |
| 140 | * affected by the authority settings defined on this installation |
| 141 | * |
| 142 | * @var array |
| 143 | */ |
| 144 | $excluded_keys = (array) apply_filters( 'tribe_tracker_excluded_meta_keys', $excluded_keys ); |
| 145 | |
| 146 | return $excluded_keys; |
| 147 | } |
| 148 | |
| 149 | /** |
| 150 | * Make sure we are tracking all meta fields related on the correct Post Types |
| 151 | * |
| 152 | * @since 4.5 |
| 153 | * |
| 154 | * @param int $meta_id Meta ID |
| 155 | * @param int $post_id Post ID. |
| 156 | * @param string $meta_key Meta key. |
| 157 | */ |
| 158 | public function register_added_deleted_meta( $meta_id, $post_id, $meta_key ) { |
| 159 | /** |
| 160 | * Allows toggling the Modified fields tracking |
| 161 | * @var bool |
| 162 | */ |
| 163 | $is_tracking_modified_fields = (bool) apply_filters( 'tribe_tracker_enabled', true ); |
| 164 | |
| 165 | // Bail if we shouldn't be tracking modifications |
| 166 | if ( false === $is_tracking_modified_fields ) { |
| 167 | return; |
| 168 | } |
| 169 | |
| 170 | // Try to fetch the post object |
| 171 | $post = get_post( $post_id ); |
| 172 | |
| 173 | // We only go forward if we have the Post Object |
| 174 | if ( ! $post instanceof WP_Post ) { |
| 175 | return; |
| 176 | } |
| 177 | |
| 178 | // Fetch from a unified method which meta keys are been excluded |
| 179 | $excluded_keys = $this->get_excluded_meta_keys(); |
| 180 | |
| 181 | // Bail when this meta is set to be excluded |
| 182 | if ( in_array( $meta_key, $excluded_keys ) ) { |
| 183 | return; |
| 184 | } |
| 185 | |
| 186 | // Fetch from a unified method which post types are been tracked |
| 187 | $tracked_post_types = $this->get_post_types(); |
| 188 | |
| 189 | // Only track if the meta is from a post that is been tracked |
| 190 | if ( ! in_array( $post->post_type, $tracked_post_types ) ) { |
| 191 | return; |
| 192 | } |
| 193 | |
| 194 | // Gets the Current Timestamp |
| 195 | $now = current_time( 'timestamp' ); |
| 196 | |
| 197 | // Fetch the current data from the modified fields |
| 198 | $modified = get_post_meta( $post->ID, self::$field_key, true ); |
| 199 | if ( ! is_array( $modified ) ) { |
| 200 | $modified = []; |
| 201 | } |
| 202 | |
| 203 | // If we got here we will update the Modified Meta |
| 204 | $modified[ $meta_key ] = $now; |
| 205 | |
| 206 | // Actually do the Update |
| 207 | update_post_meta( $post->ID, self::$field_key, $modified ); |
| 208 | } |
| 209 | |
| 210 | /** |
| 211 | * Make sure we are tracking all meta fields related to the correct Post Types |
| 212 | * |
| 213 | * @since 4.5 |
| 214 | * |
| 215 | * @param null|bool $check Whether to allow updating metadata for the given type. |
| 216 | * @param int $post_id Post ID. |
| 217 | * @param string $meta_key Meta key. |
| 218 | * @param mixed $meta_value Meta value. Must be serializable if non-scalar. |
| 219 | * @param mixed $prev_value Previous Value of the Meta, allowing to check the data |
| 220 | * |
| 221 | * @return null|bool This should be ignored, only used to not break the WordPress filters |
| 222 | */ |
| 223 | public function filter_watch_updated_meta( $check, $post_id, $meta_key, $meta_value, $prev_value = null ) { |
| 224 | /** |
| 225 | * Allows toggling the Modified fields tracking |
| 226 | * @var bool |
| 227 | */ |
| 228 | $is_tracking_modified_fields = (bool) apply_filters( 'tribe_tracker_enabled', true ); |
| 229 | |
| 230 | // Bail if we shouldn't be tracking modifications |
| 231 | if ( false === $is_tracking_modified_fields ) { |
| 232 | return $check; |
| 233 | } |
| 234 | |
| 235 | // Matching the WordPress filter, we actually don't care about Check at all! |
| 236 | if ( null !== $check ) { |
| 237 | return (bool) $check; |
| 238 | } |
| 239 | |
| 240 | // Try to fetch the post object |
| 241 | $post = get_post( $post_id ); |
| 242 | |
| 243 | // We only go forward if we have the Post Object |
| 244 | if ( ! $post instanceof WP_Post ) { |
| 245 | return $check; |
| 246 | } |
| 247 | |
| 248 | // Fetch from a unified method which meta keys are been excluded |
| 249 | $excluded_keys = $this->get_excluded_meta_keys(); |
| 250 | |
| 251 | // Bail when this meta is set to be excluded |
| 252 | if ( in_array( $meta_key, $excluded_keys ) ) { |
| 253 | return $check; |
| 254 | } |
| 255 | |
| 256 | // Fetch from a unified method which post types are been tracked |
| 257 | $tracked_post_types = $this->get_post_types(); |
| 258 | |
| 259 | // Only track if the meta is from a post that is been tracked |
| 260 | if ( ! in_array( $post->post_type, $tracked_post_types ) ) { |
| 261 | return $check; |
| 262 | } |
| 263 | |
| 264 | if ( empty( $prev_value ) ) { |
| 265 | $prev_value = get_post_meta( $post->ID, $meta_key, true ); |
| 266 | } |
| 267 | |
| 268 | // We don't care if the value didn't actually change |
| 269 | if ( $prev_value == $meta_value ) { |
| 270 | return $check; |
| 271 | } |
| 272 | |
| 273 | // Gets the Current Timestamp |
| 274 | $now = current_time( 'timestamp' ); |
| 275 | |
| 276 | // Fetch the current data from the modified fields |
| 277 | $modified = get_post_meta( $post->ID, self::$field_key, true ); |
| 278 | if ( ! is_array( $modified ) ) { |
| 279 | $modified = []; |
| 280 | } |
| 281 | |
| 282 | // If we got here we will update the Modified Meta |
| 283 | $modified[ $meta_key ] = $now; |
| 284 | |
| 285 | // Actually do the Update |
| 286 | update_post_meta( $post->ID, self::$field_key, $modified ); |
| 287 | |
| 288 | // We need to return this, because we are still on a filter |
| 289 | return $check; |
| 290 | } |
| 291 | |
| 292 | /** |
| 293 | * Tracks fields that are changed when an event is updated |
| 294 | * |
| 295 | * @param int $post_id Post ID |
| 296 | * @param WP_Post $post_after New post object |
| 297 | * @param WP_Post $post_before Old post object |
| 298 | */ |
| 299 | public function filter_watch_post_fields( $post_id, $post_after, $post_before ) { |
| 300 | /** |
| 301 | * Allows toggling the Modified fields tracking |
| 302 | * @var bool |
| 303 | */ |
| 304 | $is_tracking_modified_fields = (bool) apply_filters( 'tribe_tracker_enabled', true ); |
| 305 | |
| 306 | // Bail if we shouldn't be tracking modifications |
| 307 | if ( false === $is_tracking_modified_fields ) { |
| 308 | return; |
| 309 | } |
| 310 | |
| 311 | // Fetch from a unified method which post types are been tracked |
| 312 | $tracked_post_types = $this->get_post_types(); |
| 313 | |
| 314 | // Only track if the meta is from a post that is been tracked |
| 315 | if ( ! in_array( $post_before->post_type, $tracked_post_types ) ) { |
| 316 | return; |
| 317 | } |
| 318 | |
| 319 | // Fetch the current Time |
| 320 | $now = current_time( 'timestamp' ); |
| 321 | |
| 322 | if ( ! $modified = get_post_meta( $post_id, self::$field_key, true ) ) { |
| 323 | $modified = []; |
| 324 | } |
| 325 | |
| 326 | $fields_to_check_for_changes = [ |
| 327 | 'post_title', |
| 328 | 'post_content', |
| 329 | 'post_excerpt', |
| 330 | 'post_status', |
| 331 | 'post_type', |
| 332 | 'post_parent', |
| 333 | ]; |
| 334 | |
| 335 | foreach ( $fields_to_check_for_changes as $field ) { |
| 336 | if ( ! $this->has_field_changed( $field, $post_after, $post_before ) ) { |
| 337 | continue; |
| 338 | } |
| 339 | |
| 340 | $modified[ $field ] = $now; |
| 341 | } |
| 342 | |
| 343 | if ( $modified ) { |
| 344 | update_post_meta( $post_id, self::$field_key, $modified ); |
| 345 | } |
| 346 | } |
| 347 | |
| 348 | /** |
| 349 | * Track term changes for the tracked post types and terms. |
| 350 | * |
| 351 | * Meant to run on the `set_object_terms` action. |
| 352 | * |
| 353 | * @see wp_set_object_terms() |
| 354 | * |
| 355 | * @param $object_id |
| 356 | * @param $terms |
| 357 | * @param $tt_ids |
| 358 | * @param $taxonomy |
| 359 | * @param $append |
| 360 | * @param $old_tt_ids |
| 361 | * |
| 362 | * @return bool `true` if the post type and taxonomy are tracked, `false` otherwise. |
| 363 | */ |
| 364 | public function track_taxonomy_term_changes( $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids ) { |
| 365 | /** |
| 366 | * Allows toggling the post taxonomy terms tracking |
| 367 | * |
| 368 | * @var bool $track_terms Whether the class is currently tracking terms or not. |
| 369 | */ |
| 370 | $is_tracking_taxonomy_terms = (bool) apply_filters( 'tribe_tracker_enabled_for_terms', $this->track_terms ); |
| 371 | |
| 372 | if ( false === $is_tracking_taxonomy_terms ) { |
| 373 | return false; |
| 374 | } |
| 375 | |
| 376 | $tracked_post_types = $this->get_post_types(); |
| 377 | |
| 378 | $post_id = tribe_post_exists( $object_id ); |
| 379 | |
| 380 | if ( |
| 381 | empty( $post_id ) |
| 382 | || ! ( $post = get_post( $post_id ) ) |
| 383 | || ! in_array( $post->post_type, $tracked_post_types ) |
| 384 | ) { |
| 385 | return false; |
| 386 | } |
| 387 | |
| 388 | $tracked_taxonomies = $this->get_taxonomies(); |
| 389 | |
| 390 | if ( ! in_array( $taxonomy, $tracked_taxonomies ) ) { |
| 391 | return false; |
| 392 | } |
| 393 | |
| 394 | if ( ! $modified = get_post_meta( $post->ID, self::$field_key, true ) ) { |
| 395 | $modified = []; |
| 396 | } |
| 397 | |
| 398 | if ( $tt_ids == $old_tt_ids ) { |
| 399 | // nothing to update, still we did the job |
| 400 | return true; |
| 401 | } |
| 402 | |
| 403 | $modified[ $taxonomy ] = time(); |
| 404 | update_post_meta( $post->ID, self::$field_key, $modified ); |
| 405 | |
| 406 | return true; |
| 407 | } |
| 408 | |
| 409 | /** |
| 410 | * Easy way to see currently which taxonomies are been tracked by our code. |
| 411 | * |
| 412 | * @return array |
| 413 | */ |
| 414 | public function get_taxonomies() { |
| 415 | /** |
| 416 | * Adds a way for Developers to add and remove which taxonomies will be tracked |
| 417 | * |
| 418 | * Note: Removing any of the default methods will affect how we deal with fields |
| 419 | * affected by the authority settings defined on this installation |
| 420 | * |
| 421 | * @var array $tracked_taxonomies An array of the tracker taxonomies names. |
| 422 | */ |
| 423 | $tracked_taxonomies = (array) apply_filters( 'tribe_tracker_taxonomies', $this->tracked_taxonomies ); |
| 424 | |
| 425 | return $tracked_taxonomies; |
| 426 | } |
| 427 | |
| 428 | /** |
| 429 | * Whether taxonomy term changes should be tracked or not by the class. |
| 430 | * |
| 431 | * @param bool $track_terms |
| 432 | */ |
| 433 | public function should_track_terms( $track_terms ) { |
| 434 | $this->track_terms = $track_terms; |
| 435 | } |
| 436 | |
| 437 | /** |
| 438 | * Sets the taxonomies the tracker should track. |
| 439 | * |
| 440 | * @param array $tracked_taxonomies |
| 441 | */ |
| 442 | public function set_tracked_taxonomies( array $tracked_taxonomies ) { |
| 443 | $this->tracked_taxonomies = $tracked_taxonomies; |
| 444 | } |
| 445 | |
| 446 | /** |
| 447 | * Sets the post types the tracker should track. |
| 448 | * |
| 449 | * @param array $tracked_post_types |
| 450 | */ |
| 451 | public function set_tracked_post_types( array $tracked_post_types ) { |
| 452 | $this->tracked_post_types = $tracked_post_types; |
| 453 | } |
| 454 | |
| 455 | /** |
| 456 | * Make sure to remove the changed field if the event is deleted to ensure there are no left meta fields when |
| 457 | * the event is deleted. |
| 458 | * |
| 459 | * @since 4.7.6 |
| 460 | * |
| 461 | * @param int Post ID |
| 462 | * @return bool |
| 463 | */ |
| 464 | public function cleanup_meta_fields( $post_id ) { |
| 465 | return delete_post_meta( (int) $post_id, self::$field_key ); |
| 466 | } |
| 467 | } |
| 468 |