• File: cleanup-integration.php
  • Full Path: /home/matthif/www/wp-content/plugins/wordpress-seo/src/integrations/cleanup-integration.php
  • Date Modified: 02/24/2024 11:29 PM
  • File size: 8.08 KB
  • MIME-type: text/x-php
  • Charset: utf-8
<?php

namespace Yoast\WP\SEO\Integrations;

use 
Closure;
use 
Yoast\WP\SEO\Repositories\Indexable_Cleanup_Repository;

/**
 * Adds cleanup hooks.
 */
class Cleanup_Integration implements Integration_Interface {

    
/**
     * Identifier used to determine the current task.
     */
    
public const CURRENT_TASK_OPTION 'wpseo-cleanup-current-task';

    
/**
     * Identifier for the cron job.
     */
    
public const CRON_HOOK 'wpseo_cleanup_cron';

    
/**
     * Identifier for starting the cleanup.
     */
    
public const START_HOOK 'wpseo_start_cleanup_indexables';

    
/**
     * The cleanup repository.
     *
     * @var Indexable_Cleanup_Repository
     */
    
private $cleanup_repository;

    
/**
     * The constructor.
     *
     * @param Indexable_Cleanup_Repository $cleanup_repository The cleanup repository.
     */
    
public function __constructIndexable_Cleanup_Repository $cleanup_repository ) {
        
$this->cleanup_repository $cleanup_repository;
    }

    
/**
     * Initializes the integration.
     *
     * This is the place to register hooks and filters.
     *
     * @return void
     */
    
public function register_hooks() {
        
\add_actionself::START_HOOK, [ $this'run_cleanup' ] );
        
\add_actionself::CRON_HOOK, [ $this'run_cleanup_cron' ] );
        
\add_action'wpseo_deactivate', [ $this'reset_cleanup' ] );
    }

    
/**
     * Returns the conditionals based on which this loadable should be active.
     *
     * @return array The array of conditionals.
     */
    
public static function get_conditionals() {
        return [];
    }

    
/**
     * Starts the indexables cleanup.
     *
     * @return void
     */
    
public function run_cleanup() {
        
$this->reset_cleanup();

        
$cleanups $this->get_cleanup_tasks();
        
$limit    $this->get_limit();

        foreach ( 
$cleanups as $name => $action ) {
            
$items_cleaned $action$limit );

            if ( 
$items_cleaned === false ) {
                return;
            }

            if ( 
$items_cleaned $limit ) {
                continue;
            }

            
// There are more items to delete for the current cleanup job, start a cronjob at the specified job.
            
$this->start_cron_job$name );

            return;
        }
    }

    
/**
     * Returns an array of cleanup tasks.
     *
     * @return Closure[] The cleanup tasks.
     */
    
public function get_cleanup_tasks() {
        return 
\array_merge(
            [
                
'clean_indexables_with_object_type_and_object_sub_type_shop_order' => function ( $limit ) {
                    return 
$this->cleanup_repository->clean_indexables_with_object_type_and_object_sub_type'post''shop_order'$limit );
                },
                
'clean_indexables_by_post_status_auto-draft' => function ( $limit ) {
                    return 
$this->cleanup_repository->clean_indexables_with_post_status'auto-draft'$limit );
                },
                
'clean_indexables_for_non_publicly_viewable_post' => function ( $limit ) {
                    return 
$this->cleanup_repository->clean_indexables_for_non_publicly_viewable_post$limit );
                },
                
'clean_indexables_for_non_publicly_viewable_taxonomies' => function ( $limit ) {
                    return 
$this->cleanup_repository->clean_indexables_for_non_publicly_viewable_taxonomies$limit );
                },
                
'clean_indexables_for_non_publicly_viewable_post_type_archive_pages' => function ( $limit ) {
                    return 
$this->cleanup_repository->clean_indexables_for_non_publicly_viewable_post_type_archive_pages$limit );
                },
                
'clean_indexables_for_authors_archive_disabled' => function ( $limit ) {
                    return 
$this->cleanup_repository->clean_indexables_for_authors_archive_disabled$limit );
                },
                
'clean_indexables_for_authors_without_archive' => function ( $limit ) {
                    return 
$this->cleanup_repository->clean_indexables_for_authors_without_archive$limit );
                },
                
'update_indexables_author_to_reassigned' => function ( $limit ) {
                    return 
$this->cleanup_repository->update_indexables_author_to_reassigned$limit );
                },
                
'clean_orphaned_user_indexables_without_wp_user' => function ( $limit ) {
                    return 
$this->cleanup_repository->clean_indexables_for_orphaned_users$limit );
                },
                
'clean_orphaned_user_indexables_without_wp_post' => function ( $limit ) {
                    return 
$this->cleanup_repository->clean_indexables_for_object_type_and_source_table'posts''ID''post'$limit );
                },
                
'clean_orphaned_user_indexables_without_wp_term' => function ( $limit ) {
                    return 
$this->cleanup_repository->clean_indexables_for_object_type_and_source_table'terms''term_id''term'$limit );
                },
            ],
            
$this->get_additional_tasks(),
            [
                
/* These should always be the last ones to be called. */
                
'clean_orphaned_content_indexable_hierarchy' => function ( $limit ) {
                    return 
$this->cleanup_repository->cleanup_orphaned_from_table'Indexable_Hierarchy''indexable_id'$limit );
                },
                
'clean_orphaned_content_seo_links_indexable_id' => function ( $limit ) {
                    return 
$this->cleanup_repository->cleanup_orphaned_from_table'SEO_Links''indexable_id'$limit );
                },
                
'clean_orphaned_content_seo_links_target_indexable_id' => function ( $limit ) {
                    return 
$this->cleanup_repository->cleanup_orphaned_from_table'SEO_Links''target_indexable_id'$limit );
                },

            ]
        );
    }

    
/**
     * Gets additional tasks from the 'wpseo_cleanup_tasks' filter.
     *
     * @return Closure[] Associative array of cleanup functions.
     */
    
private function get_additional_tasks() {

        
/**
         * Filter: Adds the possibility to add addition cleanup functions.
         *
         * @param array $additional_tasks Associative array with unique keys. Value should be a cleanup function that receives a limit.
         */
        
$additional_tasks \apply_filters'wpseo_cleanup_tasks', [] );

        if ( ! 
\is_array$additional_tasks ) ) {
            return [];
        }

        foreach ( 
$additional_tasks as $key => $value ) {
            if ( 
\is_int$key ) ) {
                return [];
            }
            if ( ( ! 
\is_object$value ) ) || ! ( $value instanceof Closure ) ) {
                return [];
            }
        }

        return 
$additional_tasks;
    }

    
/**
     * Gets the deletion limit for cleanups.
     *
     * @return int The limit for the amount of entities to be cleaned.
     */
    
private function get_limit() {
        
/**
         * Filter: Adds the possibility to limit the number of items that are deleted from the database on cleanup.
         *
         * @param int $limit Maximum number of indexables to be cleaned up per query.
         */
        
$limit \apply_filters'wpseo_cron_query_limit_size'1000 );

        if ( ! 
\is_int$limit ) ) {
            
$limit 1000;
        }

        return 
\abs$limit );
    }

    
/**
     * Resets and stops the cleanup integration.
     *
     * @return void
     */
    
public function reset_cleanup() {
        
\delete_optionself::CURRENT_TASK_OPTION );
        
\wp_unschedule_hookself::CRON_HOOK );
    }

    
/**
     * Starts the cleanup cron job.
     *
     * @param string $task_name The task name of the next cleanup task to run.
     *
     * @return void
     */
    
private function start_cron_job$task_name ) {
        
\update_optionself::CURRENT_TASK_OPTION$task_name );
        
\wp_schedule_event(
            ( 
\time() + \HOUR_IN_SECONDS ),
            
'hourly',
            
self::CRON_HOOK
        
);
    }

    
/**
     * The callback that is called for the cleanup cron job.
     *
     * @return void
     */
    
public function run_cleanup_cron() {
        
$current_task_name \get_optionself::CURRENT_TASK_OPTION );

        if ( 
$current_task_name === false ) {
            
$this->reset_cleanup();

            return;
        }

        
$limit $this->get_limit();
        
$tasks $this->get_cleanup_tasks();

        
// The task may have been added by a filter that has been removed, in that case just start over.
        
if ( ! isset( $tasks$current_task_name ] ) ) {
            
$current_task_name \key$tasks );
        }

        
$current_task \current$tasks );
        while ( 
$current_task !== false ) {
            
// Skip the tasks that have already been done.
            
if ( \key$tasks ) !== $current_task_name ) {
                
$current_task \next$tasks );
                continue;
            }

            
// Call the cleanup callback function that accompanies the current task.
            
$items_cleaned $current_task$limit );

            if ( 
$items_cleaned === false ) {
                
$this->reset_cleanup();

                return;
            }

            if ( 
$items_cleaned === ) {
                
// Check if we are finished with all tasks.
                
if ( \next$tasks ) === false ) {
                    
$this->reset_cleanup();

                    return;
                }

                
// Continue with the next task next time the cron job is run.
                
\update_optionself::CURRENT_TASK_OPTION\key$tasks ) );

                return;
            }

            
// There were items deleted for the current task, continue with the same task next cron call.
            
return;
        }
    }
}