钩子文档

pre_move_uploaded_file

💡 云策文档标注

概述

pre_move_uploaded_file 是一个 WordPress 过滤器,用于在文件上传通过所有检查后,决定是否跳过移动文件的操作。如果过滤器返回非 null 值,将完全跳过文件移动和相关错误报告。

关键要点

  • 过滤器允许开发者自定义文件上传后的处理逻辑,例如复制文件而非移动。
  • 参数包括 $move_new_file(控制是否移动文件)、$file(引用 $_FILES 数组元素)、$new_file(新文件名)和 $type(新文件 MIME 类型)。
  • 常用于 _wp_handle_upload() 函数中,影响 wp_handle_sideload() 和 media_handle_sideload() 等上传处理流程。

代码示例

add_filter( 'pre_move_uploaded_file', function( $move, $file, $new_file ) {
    // 复制文件而非移动
    $move = @copy( $file['tmp_name'], $new_file );
    if ( false === $move && WP_DEBUG ) {
        trigger_error( ... ); // 错误处理
    }
    return $move; // 返回 true/false 以跳过默认移动
}, 10, 3 );

注意事项

  • 使用此过滤器时,需确保文件路径已通过 WordPress 验证,避免安全风险。
  • 示例代码仅复制文件到上传目录,不自动创建媒体附件或关联到文章,需额外处理。
  • 过滤器从 WordPress 4.9.0 版本引入,适用于高级上传场景定制。

📄 原文内容

Filters whether to short-circuit moving the uploaded file after passing all checks.

Description

If a non-null value is returned from the filter, moving the file and any related error reporting will be completely skipped.

Parameters

$move_new_filemixed
If null (default) move the file after the upload.
$filearray
Reference to a single element from $_FILES.

  • name string
    The original name of the file on the client machine.
  • type string
    The mime type of the file, if the browser provided this information.
  • tmp_name string
    The temporary filename of the file in which the uploaded file was stored on the server.
  • size int
    The size, in bytes, of the uploaded file.
  • error int
    The error code associated with this file upload.

$new_filestring
Filename of the newly-uploaded file.
$typestring
Mime type of the newly-uploaded file.

Source

$move_new_file = apply_filters( 'pre_move_uploaded_file', null, $file, $new_file, $type );

Changelog

Version Description
4.9.0 Introduced.

User Contributed Notes

  1. Skip to note 2 content

    There is an interesting question on this filter in the support forum with a rather complicated reply, however, I have to use this for a slightly different problem.

    I normally use the function media_handle_sideload() to move a file into the wp uploads fodler and save it as a media attachment post, which works quite nicely.

    However, recently I had to copy a file (rather than move it), in my plugin extension as the original plugin still needed to have access to the original file location (a temporary folder on the fs), and unfortunately there is no way to get the media_handle_sideload() to copy rather than move a file.

    This is where this filter comes in handy. The media_handle_sideload() makes use of the wp_handle_sideload(), which in turns calls the _wp_handle_upload() function, within which the pre_move_uploaded_file filter is applied.

    The filter can be used to switch off the actual moving of the file while retaining all the goodness of validation that the function handles, allowing one to handle the actual file handling, copying it instead of moving it in my case. This is how I used it,

    // first step is to identify the filename and path you want to copy. 
    $file_arr = array(
    	'name'     => $filename, //something like my-photo.jpg
    	'tmp_name' => $path, //something like /..../wp-content/uploads/cf7-uploads/tmp/my-photo.jpg
    );
    
    // next use a unique action handle to identify your file process from others handled by WP core/plugins.
    $action = 'wpdocs_file_copy';
    
    // this allows to identify your file action with the filter applied at the start of _wp_handle_upload().
    // register your file handling process with an anonymous function.
    add_filter( "{$action}_prefilter", function( $file ) {
    	// next we hook the filter to cancel the file move.
    	add_filter( 'pre_move_uploaded_file', function( $move, $file, $new_file ) {
    	
    		// now you copy your file, knowing that the $new_file path has been validated by WP.
    		$move = @copy( $file['tmp_name'], $new_file );
    		
    		if ( false === $move && WP_DEBUG ) {
    			trigger_error( ... ); // handle the error (optional). 
    		}
    		
    		return $move; // either false or true, but not null will cancel the file move.
    	}, 10, 3 ); // pre_move filter
    	
    	return $file;
    } ); // filter
    
    // now you fire the actually file moving process which will validate the new location of the file on the fs and trigger the above filter.
    $new_file_arr = wp_handle_sideload( $file_arr,
    	array(
    		'action'    => $action, // the action defined above.
    		'test_form' => false, // in this case the file I am copying is not coming from the $_FILES submission and so I don't need the extra validation. 
    	),
    	current_time( 'mysql' ) // timestamp.
    );
    
    if ( isset( $new_file_arr['error'] ) ) { //in case there was an error.
    	// handle the error (optional)
    } else {
    	$url      = $new_file_arr['url'];
    	$type     = $new_file_arr['type'];
    	$new_file = $new_file_arr['file'];
    }
    // you can then go on to create an attachment post and link it to a parent post if need be.

    Note, the above only copies the file to the wp-content/uploads/<year>/<month>/ folder structure, but does not actually create an attachment post (required to see your file in the Media section of the dashboard), nor links it to a parent post (eg as a featured/thumbnail image). If you need to see how to do this I suggest you take a look at the process used in the media_handle_sideload() function.