Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seanlanglands/948ba1ba8817ed64d5e0fa4592f082f3 to your computer and use it in GitHub Desktop.
Save seanlanglands/948ba1ba8817ed64d5e0fa4592f082f3 to your computer and use it in GitHub Desktop.
Determine whether the file is private or public based on post meta value
<?php
add_filter( 'vip_files_acl_file_visibility', 'check_file_visibility_by_metadata', 11, 2 );
/**
* Given a path determine whether the file is private or public based on the
* value of the attachment's `_custom_restriction_meta` post meta.
*
* @param string $file_visibility one of Automattic\VIP\Files\Acl\(FILE_IS_PUBLIC | FILE_IS_PRIVATE_AND_ALLOWED | FILE_IS_PRIVATE_AND_DENIED).
* @param string $file_path path to file to be checked for visibility.
*
* @return string one of Automattic\VIP\Files\Acl\(FILE_IS_PUBLIC | FILE_IS_PRIVATE_AND_ALLOWED | FILE_IS_PRIVATE_AND_DENIED)
*/
function check_file_visibility_by_metadata( string $file_visibility, string $file_path ): string {
// Strip the `sites/ID` part for multisite URLs, because _wp_attached_file meta doesn't store it.
if ( 0 === strpos( $file_path, 'sites/' ) ) {
$file_path = preg_replace( '#^sites/\d+/#', '', $file_path );
}
// Reverse lookup for the attachment ID.
$attachment_id = get_attachment_id_from_file_path( $file_path );
if ( ! $attachment_id ) {
return $file_visibility;
}
$attachment_restrict_file_meta = get_post_meta( $attachment_id, '_custom_restriction_meta', true );
if ( (int) filter_var( $attachment_restrict_file_meta, FILTER_VALIDATE_BOOLEAN ) ) {
// Allow access to files for logged-in users.
if ( is_user_logged_in() ) {
return Automattic\VIP\Files\Acl\FILE_IS_PRIVATE_AND_ALLOWED;
} else {
return Automattic\VIP\Files\Acl\FILE_IS_PRIVATE_AND_DENIED;
}
}
return $file_visibility;
}
/**
* Variant of core's attachment_url_to_postid() function
*
* The core function accepts the full URL and has extra logic for reversing the host / home_uri().
*
* In the contexts where this is used, we are only acting on the path, so we've simplified things
* by only accepting a file path in this function.
*
* @see https://github.com/Automattic/vip-go-mu-plugins/blob/d6892abd5092274b7591ad9a4cd0aa3d9b8e4a0e/files/acl/restrict-unpublished-files.php#L59-L107
*
* @param $path (string) The path to resolve.
*
* @return (int) The found attachment ID, or 0 on failure.
*/
function get_attachment_id_from_file_path( string $path ): int {
global $wpdb;
$cache_group = 'vip-files-acl';
$cache_key = 'path_' . md5( $path );
$attachment_id = wp_cache_get( $cache_key, $cache_group );
if ( false !== $attachment_id ) {
return $attachment_id;
}
$attachment_id = 0;
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
$results = $wpdb->get_results(
$wpdb->prepare(
"SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = '_wp_attached_file' AND meta_value = %s",
$path
)
);
if ( $results ) {
// Use the first available result, but prefer a case-sensitive match, if exists.
$attachment_id = $results[0]->post_id;
if ( count( $results ) > 1 ) {
foreach ( $results as $result ) {
if ( $path === $result->meta_value ) {
$attachment_id = $result->post_id;
break;
}
}
}
}
wp_cache_set( $cache_key, $attachment_id, $cache_group, 5 * MINUTE_IN_SECONDS );
return $attachment_id;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment