webfont-loader icon indicating copy to clipboard operation
webfont-loader copied to clipboard

Use of WP_Filesystem

Open KBurkholder opened this issue 1 year ago • 0 comments

I'm using a WordPress theme that incorporates this library. Nice work, but there are some inherent issues with it that cause a hard crash.

Here's the code causing issues:

protected function get_filesystem() {
	global $wp_filesystem;

	// If the filesystem has not been instantiated yet, do it here.
	if ( ! $wp_filesystem ) {
		if ( ! function_exists( 'WP_Filesystem' ) ) {
			require_once wp_normalize_path( ABSPATH . '/wp-admin/includes/file.php' );
		}
		WP_Filesystem();
	}
	return $wp_filesystem;
}

WP_Filesystem is not intended to be used on the front-end - and shouldn't be. But I managed some hacks to get it working, at least in my environment...

First, the global $wp_filesystem may be set but not valid. So this:

if ( ! $wp_filesystem ) {

Should be:

if ( ! $wp_filesystem
or ( is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->has_errors() )
) {

Second, calling WP_Filesystem() with no arguments will fail on any system that actually needs to use WP_Filesystem - those that require FTP/SSH to access files.

What should be passed to WP_Filesystem() is an array of connection parameters. Those parameters should be retrieved by using request_filesystem_credentials() but that has the potential of displaying the "Connection Information" form, which we certainly don't want on the front end.

So, I added this:

if (! WP_Filesystem( get_option('ftp_credentials') ) ) {

which attempts to get the saved credentials - assuming that the administrator has saved credentials previously, and that those credentials are complete (WordPress doesn't save password or keys).

Lastly, since the above doesn't ensure that we actually have a valid $wp_filesystem, we need a fall-back...

if (!class_exists('WP_Filesystem_Direct')) {
	require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
	require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php';
}
$wp_filesystem = new WP_Filesystem_Direct([]);

This at least gives us 'direct' access, which may fail on some systems.

So here's my version of the get_filesystem method. It's far from perfect, and won't work correctly in some cases, but it works in my environment. I do recommend that the administrator set all appropriate FS_* constants in wp-config.php.

protected function get_filesystem() {
	global $wp_filesystem;

	// If the filesystem has not been instantiated yet, do it here.
	if ( ! $wp_filesystem
	or ( is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->has_errors() )
	) {
		if ( ! function_exists( 'WP_Filesystem' ) ) {
			require_once wp_normalize_path( ABSPATH . '/wp-admin/includes/file.php' );
		}
		if (! WP_Filesystem( get_option('ftp_credentials') ) ) {
			if (!class_exists('WP_Filesystem_Direct')) {
				require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
				require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php';
			}
			$wp_filesystem = new WP_Filesystem_Direct([]);
		}
	}
	return $wp_filesystem;
}

I hope this is helpful.

KBurkholder avatar Oct 26 '23 00:10 KBurkholder