'; var_dump($var); echo ''; if ($die) { die(); } } } /** * Normalize and validate a URL, ensuring it has a proper scheme (https://). * * This function automatically adds https:// if missing and validates the URL * using WordPress built-in functions. * * @param string $url The URL to normalize. * @return string The normalized URL with https:// scheme, or empty string if invalid. */ if (!function_exists('advmo_normalize_url')) { function advmo_normalize_url(string $url): string { // Return empty string if URL is empty if (empty($url)) { return ''; } // Trim whitespace $url = trim($url); // If URL doesn't start with http:// or https://, add https:// if (!preg_match('/^https?:\/\//i', $url)) { $url = 'https://' . $url; } // Validate the URL using WordPress built-in function $validated_url = esc_url_raw($url, ['http', 'https']); // Double-check with filter_var for extra validation if ($validated_url && filter_var($validated_url, FILTER_VALIDATE_URL)) { return $validated_url; } // If validation fails, log a warning and return empty string if (defined('WP_DEBUG') && WP_DEBUG) { error_log(sprintf( 'ADVMO Warning: Invalid URL "%s" was provided. Please check your wp-config.php settings.', $url )); } return ''; } } /** * Helper: Get public URL for an attachment */ if (!function_exists('advmo_get_public_url')) { function advmo_get_public_url($attachment_id) { $url = wp_get_attachment_url($attachment_id); return $url; } } if (!function_exists('advmo_is_settings_page')) { function advmo_is_settings_page($page_name = ''): bool { $current_screen = get_current_screen(); if (!$current_screen) { return false; } // Get the current page from the query string $current_page = isset($_GET['page']) ? sanitize_text_field($_GET['page']) : ''; // Define our plugin pages $plugin_pages = [ 'general' => 'advmo', 'media-overview' => 'advmo_media_overview' ]; // If a specific page is requested if (!empty($page_name)) { if (!isset($plugin_pages[$page_name])) { return false; // Invalid page name provided } // Check if the current page matches the requested page return $current_page === $plugin_pages[$page_name]; } // Check if we're on any plugin page return in_array($current_page, array_values($plugin_pages)); } } /** * Generate copyright text * * @return string */ /** * Generate copyright and support text * * @return string */ if (!function_exists('advmo_get_copyright_text')) { function advmo_get_copyright_text(): string { $year = date('Y'); $site_url = 'https://wpfitter.com/?utm_source=wp-plugin&utm_medium=plugin&utm_campaign=advanced-media-offloader'; $donate = ''; if (apply_filters('advmo_show_donate_links', true)) { $donate_url = add_query_arg(array( 'utm_source' => 'wp-plugin', 'utm_medium' => 'admin-footer', 'utm_campaign' => 'advanced-media-offloader', 'utm_content' => 'footer-donate', ), 'https://buymeacoffee.com/wpfitter'); $donate = sprintf( ' %s %s', esc_html__('Enjoying the plugin?', 'advanced-media-offloader'), esc_url($donate_url), esc_attr__('Donate to support Advanced Media Offloader', 'advanced-media-offloader'), esc_html__('Donate', 'advanced-media-offloader') ); } return sprintf( 'Advanced Media Offloader plugin developed by WPFitter. %s', esc_url($site_url), $donate ); } } /** * Get bulk offload data. * * @return array The bulk offload data. */ if (!function_exists('advmo_get_bulk_offload_data')) { function advmo_get_bulk_offload_data(): array { $defaults = array( 'total' => 0, 'status' => '', 'processed' => 0, 'errors' => 0, 'last_update' => null, 'oversized_skipped' => 0 ); $stored_data = get_option('advmo_bulk_offload_data', array()); return array_merge($defaults, $stored_data); } } /** * Update bulk offload data. * * @param array $new_data The new data to update. * @return array The updated bulk offload data. */ if (!function_exists('advmo_update_bulk_offload_data')) { function advmo_update_bulk_offload_data(array $new_data): array { // Define the allowed keys $allowed_keys = array( 'total', 'status', 'processed', 'errors', 'oversized_skipped', 'last_recovery', 'last_cleanup', 'last_update' ); // Filter the new data to only include allowed keys $filtered_new_data = array_intersect_key($new_data, array_flip($allowed_keys)); // Get the existing data $existing_data = advmo_get_bulk_offload_data(); // Merge the filtered new data with the existing data $updated_data = array_merge($existing_data, $filtered_new_data); // Ensure only allowed keys are in the final data set $final_data = array_intersect_key($updated_data, array_flip($allowed_keys)); // Normalise timestamp fields. foreach (array('last_recovery', 'last_cleanup') as $timestamp_key) { if (isset($final_data[$timestamp_key])) { $final_data[$timestamp_key] = (int) $final_data[$timestamp_key]; } } // Add a timestamp for the last update if not explicitly provided. if (!isset($filtered_new_data['last_update'])) { $final_data['last_update'] = time(); } else { $final_data['last_update'] = (int) $filtered_new_data['last_update']; } // Update the option in the database update_option('advmo_bulk_offload_data', $final_data); update_option('advmo_bulk_offload_last_update', $final_data['last_update']); return $final_data; } } /** * Check if media is organized by year and month. * * @return bool True if media is organized by year and month, false otherwise. */ if (!function_exists('advmo_is_media_organized_by_year_month')) { function advmo_is_media_organized_by_year_month(): bool { return get_option('uploads_use_yearmonth_folders') ? true : false; } } /** * Sanitize a URL path. * * @param string $path The path to sanitize. * @return string The sanitized path. */ if (!function_exists('advmo_sanitize_path')) { function advmo_sanitize_path(string $path): string { // Remove leading and trailing whitespace $path = trim($path); // Remove or encode potentially harmful characters $path = wp_sanitize_redirect($path); // Convert to lowercase for consistency (optional, depending on your needs) $path = strtolower($path); // Remove any directory traversal attempts $path = str_replace(['../', './'], '', $path); // Normalize slashes and remove duplicate slashes $path = preg_replace('#/+#', '/', $path); // Remove leading and trailing slashes $path = trim($path, '/'); // Optionally, you can use wp_normalize_path() if you want to ensure consistent directory separators $path = wp_normalize_path($path); return $path; } } /** * Clear bulk offload data. * * @return void */ if (!function_exists('advmo_clear_bulk_offload_data')) { function advmo_clear_bulk_offload_data(): void { delete_option('advmo_bulk_offload_data'); } } /** * Get the cloud provider key. * * @return string The cloud provider key. */ if (!function_exists('advmo_get_cloud_provider_key')) { function advmo_get_cloud_provider_key(): string { $options = get_option('advmo_settings', []); return $options['cloud_provider'] ?? ''; } } /** * Get the count of unoffloaded media items. * * @return int The count of unoffloaded media items. */ if (!function_exists('advmo_get_unoffloaded_media_items_count')) { function advmo_get_unoffloaded_media_items_count(): int { global $wpdb; $query = "SELECT COUNT(*) FROM {$wpdb->posts} p LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND pm.meta_key = 'advmo_offloaded' WHERE p.post_type = 'attachment' AND (pm.meta_value IS NULL OR pm.meta_value = '')"; return (int) $wpdb->get_var($query); } } if (!function_exists('advmo_get_offloaded_media_items_count')) { function advmo_get_offloaded_media_items_count(): int { global $wpdb; $query = $wpdb->prepare( "SELECT COUNT(DISTINCT p.ID) FROM {$wpdb->posts} p INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id WHERE p.post_type = %s AND p.post_status != %s AND pm.meta_key = %s AND pm.meta_value != %s", array( 'attachment', 'trash', 'advmo_offloaded', '' ) ); return (int) $wpdb->get_var($query); } } /** * Check if a credential constant exists in wp-config.php * * @param string $constant_name The name of the constant to check. * @return bool True if constant is defined, false otherwise. */ if (!function_exists('advmo_credential_exists_in_config')) { function advmo_credential_exists_in_config(string $constant_name): bool { return defined($constant_name); } } /** * Get provider credentials from constants or saved options. * Constants take priority over saved options. * * @param string $provider_key The cloud provider key (e.g., 'cloudflare_r2', 'amazon_s3'). * @param string $field_name The credential field name (e.g., 'key', 'secret', 'bucket'). * @return string The credential value or empty string if not found. */ if (!function_exists('advmo_get_provider_credential')) { function advmo_get_provider_credential(string $provider_key, string $field_name): string { // Build constant name (e.g., ADVMO_CLOUDFLARE_R2_KEY) $constant_name = 'ADVMO_' . strtoupper($provider_key) . '_' . strtoupper($field_name); // Check if constant exists first (priority) if (defined($constant_name)) { $value = constant($constant_name); return is_string($value) ? $value : ''; } // Fall back to saved options $credentials = get_option('advmo_credentials', []); if (isset($credentials[$provider_key][$field_name])) { return $credentials[$provider_key][$field_name]; } return ''; } } /** * Save provider credentials to options. * * @param string $provider_key The cloud provider key. * @param array $credentials Associative array of credential fields and values. * @return bool True on success, false on failure. */ if (!function_exists('advmo_save_provider_credentials')) { function advmo_save_provider_credentials(string $provider_key, array $credentials): bool { $all_credentials = get_option('advmo_credentials', []); $all_credentials[$provider_key] = $credentials; return update_option('advmo_credentials', $all_credentials); } } /** * Get all credentials for a specific provider. * * @param string $provider_key The cloud provider key. * @return array Associative array of all credential fields for the provider. */ if (!function_exists('advmo_get_provider_credentials')) { function advmo_get_provider_credentials(string $provider_key): array { $credentials = get_option('advmo_credentials', []); return $credentials[$provider_key] ?? []; } }