Web Development

How To Download FTP Files in WordPress [Beginner’s Guide]

ways to download FTP files in WordPress

As we know, downloading FTP details in WordPress is not an easy task even for professional WordPress developers. There are many hurdles which you have to get over before downloading FTP files. The hurdles can affect especially when you are not familiar with the manipulations occurring to the file.

Here in this blog below, I’ll show you the ways to download FTP files in WordPress. Read on to learn to download WordPress FTP from scratch.

How Will It Work?

As the latest version of WordPress 4.7.1,  the WP_Filesystem_FTPext is located at  wp-admin/includes/class-wp-filesystem-ftpext.php.

In this, the FTP class lets the developer connect to an FTP server in order to abstract some common FTP commands, of which not everyone is aware.

When working with this FTP class, You can go through following steps to work out with the server you are already connected to.

Follow these just from the beginning,

  • Pick content from any file
  • Get an array of contents in which the content of the file is separated each line into its own array key
  • Then put down the entire content into a file
  • List out the directory which you are following in then
  • Copy files from the FTP server

Also, certain files attribute-related methods are there :

  • Chmod a file
  • Know the owner of the file
  • Get the chmod of the file
  • Then, get the group of a file
  • Determine the size of the remote file
  • Know whether it can be read or not

Hence, this is a robust class for abstracting certain FTP operations;

So what to be done next?

As we know, WordPress already consumes these FTP class to make certain updates, manage few plugins and many other tasks done by WordPress. But, when it comes to this special case, you must get the file from a remote server, make it an attachment before import the file.

Hence, if we begin from scratch, the basic necessity is to connect with FTP. Once you are connected to FTP, you will get all the things you need. For the easy understanding of our readers, in this article, we will explain every detail in just simple class. So, move on reading to know more!


class example {


* Instance of example

* @var example


public static $inst = null;

public static function init() {

if ( null == self::$inst ) {

self::$inst = new self();


return self::$inst;


public function hooks() {

// All hooks here.

add_action( ‘init’, array( $this, ‘main’ ) );


public function main() {

// Fancy stuff here



function example_callback() {

return example::init();


add_action( ‘plugins_loaded’, array( example_callback(), ‘hooks’ ) );

So now, we are having the basic necessities, we now must jump into making the connection with the server. We can do that with our main method of a singleton. Your FTP details should never be saved in code or in a database.

Generally, this process is not done on all the init of WordPress, so we use a $_GET flag which allows executing a download for the testing purpose.

                        if ( ! isset( $_GET[‘download’] ) ) {



Moving on, we need to make sure that we are provided the access to the classes we require. So firstly, check if the classes are available. If they aren’t available, load the classes in. We will require wp_tempname() mainly for this occasion. Since the FTPext class is mandatory, it will extend Filesystem_Base, and it is impossible to have any one of them.

// First load the necessary classes

if ( ! function_exists( ‘wp_tempname’ ) ) {

require_once( ABSPATH . ‘wp-admin/includes/file.php’ );


if ( ! class_exists( ‘WP_Filesystem_Base’ ) ) {

require_once( ABSPATH . ‘wp-admin/includes/class-wp-filesystem-base.php’ );


if ( ! class_exists( ‘WP_Filesystem_FTPext’ ) ) {

require_once( ABSPATH . ‘wp-admin/includes/class-wp-filesystem-ftpext.php’ );


Earlier, issues have been found with the FS_CONNECT_TIMEOUT, as it’s constant could not get defined. So, it was determined by us that FTP class is a necessity. Hence, it is not at all a sensible task to load the entire class into memory only for the single constant.

// Typically this is not defined, so we set it up just in case

                        if ( ! defined( ‘FS_CONNECT_TIMEOUT’ ) ) {

define( ‘FS_CONNECT_TIMEOUT’, 30 );


After completing this kind of mandatory stuff and passing all the checks, Setup your connection arguments, so that you can connect() to the FTP server without any failure or hurdles.


* You DO NOT want to hard-code this, these values are here specifically for

* testing purposes.


$connection_arguments = array(

‘port’ => 21,

‘hostname’ => ‘’,

‘username’ => ”,

‘password’ => ”,


$connection = new WP_Filesystem_FTPext( $connection_arguments );

$connected = $connection->connect();

if ( ! $connected ) {

return false;


What after connection?

Finally, you are connected!

So, if you have made these efforts, you are sure that you want to download an FTP file. Now, let us download the file and import it as an attachment. Get ready first, as now you are going to face a huge amount of code in order to complete the task.

This was just a beginning!

So, firstly the most basic thing! Make sure that the file which you want to download is really a file or any other thing. To complete this task, make use of is_file(), it is a complete method located in our connection made by us previously. If the file is not a file we bail!

                        $remote_file = “x.csv”;

// Yep, you can use paths as well.

// $remote_file = “some/remote-file.txt”;

if ( ! $connection->is_file( $remote_file ) ) {



WOW! We have a file.

Now go ahead, by using the get_contents() method which will help you grab the content of the remote file into the PHP memory so that the content can be used at any other place later on.

// Get the contents of the file into memory.

$remote_contents = $connection->get_contents( $remote_file );

if ( empty( $remote_contents ) ) {



Now, before moving ahead, let me move a little. For some context, I ‘ll let you have a look at get_contents() method of WP_Filesystem_FTPext class.

Now, follow the following method and you are almost near to the completion of the process!

  • Create a temporary file using wp_tempname()
  • Open the file with fopen, keep in mind, if it does not open, it will bail.
  • Run ftp_fget to stream the remote file into the new temporary file just made. If it cannot run, bail. PHP’s native FTP method is used to run.
  • Rewind the temp file pointer back to zero. It would be similar to a VHS tape;

Now, the file reads the entire temp file into memory and returns it, similar to file_get_contents()

So, what next?

We won’t have access to this temp file name. So, we would recreate the entire method in which we streamed the file, similar to the current method done. But why is it necessary to recreate the method! Check out on WP_Filesystem_FTPext::get_contents() to check out what the response is. You will get the problem below.

So, now as we have remote content saved in our memory, we must create our own file, even if we know that it was created by core earlier in the above step. We can’t access it directly, the biggest problem. Below the snippet, you will notice that we are just checking if the file is read-only or can even be edited!

We are doing this because use file_put_contents() to import the data from the memory into the file. But if the pushing of the data does not complete, or we find the temp file in read-only format, we must bail and clean up the data with unlink(). You must be kind to the server.

            // Create a temporary file to store our data.

$temp_file = wp_tempname( $remote_file );

if ( ! is_writable( $temp_file ) || false === file_put_contents( $temp_file, $remote_contents ) ) {

unlink( $temp_file );



A little more data is now required to make the side-load functionality with which we are making ourselves to dive into. The code for wp_handle_sideload() does hard-code, but in this example, you should use wp_check_filetype(), which will make you check the mime type against any extra registered type. If the type is not found for our file extension, we should easily exit and again clean up the data.

// Optimally you want to check the file type against a WordPress method, or you can hard-code it.

                        $mime_data = wp_check_filetype( $remote_file );

if ( ! isset( $mime_data[‘type’] ) ) {

// WE just don’t have a type registered for this attachment

unlink( $temp_file ); // Cleanup



YEY! We are about to finish!

Coming up is the easiest part of the entire process which is to side-load into the uploads directory. All the file arrays were copied from the sideload example in the codex. Therefore, keep in mind that it is not necessary to re-invent the wheel. Sometimes, it is an exception in the code. For an inst, $temp_file, which was created by us, already exists, and also the mime-type from a core is also grabbed earlier, instead of hard-coding, we can also use the file string which was made earlier and is defined above as the name given is a side-loaded file.


* The following arrays are pretty much a copy/paste from the Codex, no need

* to re-invent the wheel.

* @link https://codex.wordpress.org/Function_Reference/wp_handle_sideload#Examples


$file_array = array(

‘name’     => basename( $remote_file ),

‘type’     => $mime_data[‘type’],

‘tmp_name’ => $temp_file,

‘error’    => 0,

‘size’     => filesize( $temp_file ),


$overrides = array(

‘test_form’   => false,

‘test_size’   => true,

‘test_upload’ => true,


// Side loads the content into the wp-content/uploads directory.

$sideloaded = wp_handle_sideload( $file_array, $overrides );

if ( ! empty( $sideloaded[‘error’] ) ) {



If the process gets over without any heavy error or hurdle, you will surely get an array back like the below with the help of wp_handle_sideload() method:


‘file’ => ‘/var/www/example.com/wp-content/uploads/2016/08/x.csv’

‘url’ => ‘http://example.com/wp-content/uploads/2016/08/x.csv’

‘type’ => ‘text/csv’


And finally, we are near to the end. Yes! The download is just a little away. Till now, we have achieved our goal to download a file from an FTP server. Then, stored it as a temporary file, and after that, utilized WordPress core methods in order to sideload it. But, the process is not yet entirely done. A small process is still left! Read below and get to know.

WordPress does not have any program to know the files that are in uploads directory automatically. And here comes the important role of a database. The database is kept to use your newly downloaded file as an attachment. Firstly, we need to create an attachment, which is not a huge process basically, but can be done by the few lines of codes shown below:

// Will return a 0 if for some reason insertion fails. 

                        $attachment_id = wp_insert_attachment( array(

‘guid’           => $sideloaded[‘url’], // wp_handle_sideload() will have a URL array key which is the absolute URL including HTTP

‘post_mime_type’ => $sideloaded[‘type’], // wp_handle_sideload() will have a TYPE array key, so we use this in case it was filtered somewhere

‘post_title’     => preg_replace( ‘/\.[^.]+$/’, ”, basename( $remote_file ) ), // Again copy/paste from codex

‘post_content’   => ”,

‘post_status’    => ‘inherit’,

), $sideloaded[‘file’] ); // wp_handle_sideload() will have a file array key,

so we use this in case it was filtered

// SUCCESSSSSSSSS!!!!!!!!!!!

And here comes the use of array data which was received by us from wp_handle_sideload(). After all, we will use what is given to us by WordPress, if some changes are occurred due to some of the other reason!

And It Is Done! Great!

We have finally downloaded a file from the FTP server and have also created an attachment for the file which is downloaded by us. The above article includes what are the possibilities with FTP downloads in WordPress. There are many other processes by which the download process can be made with the use of CSV’s to import, FTP image downloads and many more.

In the end, I would just hope that this was found helpful to you and have provided some possibilities to make this hard task into some easy steps. Let us know if it did!

Show More

Leave a Reply

Your email address will not be published. Required fields are marked *