Symlinks and Assumed Write Access
Learn how to create symbolic links from the code directory to a file.
Some modules and plugins create files within hard-coded paths outside of the standard path for the given framework, which can be problematic on Pantheon.
Standard File Path
Pantheon provides one location for files that are part of your site's content, like those that are managed through Drupal upload forms, e.g., user profile pictures: /sites/default/files
. For Drupal sites, this is the default location for files that are uploaded as part of your application.
For WordPress sites, /wp-content/uploads
is the default location for files. All other locations are considered part of your codebase, and under version control.
These directories are symbolically linked to Pantheon's cloud-based filesystem, Valhalla, which is writeable on all environments.
Extensions that create files within the codebase (e.g.,wp-content/plugins/plugin-name/some-other-directory
, or /sites/all/modules/module-name/some-other-directory
) incorrectly assume write access that is not granted on the Live and Test environments.
Custom configurations that use non-standard file paths (e.g.,sites/default/blogfiles
) are also incompatible with Pantheon.
The best solution is to communicate with the maintainer of the module, plugin, or custom code/configuration and request that hard-coded, nonstandard paths be fixed. Alternatively, you can create a symbolic link (symlink) as a workaround to avoid failures on Test and Live.
Create a Symbolic Link
We do not recommend creating symlinks over SFTP due to inconsistencies between clients.
The following is for Mac and Linux only. Windows users may refer to Microsoft documentation for opening Command Prompt as an Administrator and creating symlinks using mklink or create symlinks within a virtual machine.
On your Dev environment's Dashboard, change the Connection Mode from SFTP to Git mode. Install Git and clone the code locally if you have not done so already.
From your terminal,
cd
to the site code repository:cd ~/sites/myawesomesite/ #Change this to your project directory.
Move the directory you want to replace with a symlink. This serves to both back up any data that may otherwise be lost, and to prevent the symlink from being nested inside the existing directory:
mv ./wp-content/path/plugin-expects-write-to ~/backups
The command above moves the directory to a local
backups
directory in your home folder. Replace this with your preferred backup location. Note that this backup is now outside and separate from your site's codebase, and is only a safety measure to prevent data loss. Once you've confirmed that the symlink works across all environments and no data has been lost, you can remove this backup.Use the
cd
command to change to the location where the symlink will live. The symlink command (ln
) is sensitive to the working directory - the folder your command line prompt is currently in. Working from the location of the symlink allows for correct relative paths:cd wp-content/path/
Create a symlink for the standard files path:
# The first path will be used as the new file destination instead of whatever path the plugin assumed write access to ln -s ../uploads/new-directory #The last nested directory should mirror the directory name the plugin expects to write to
About ln Arguments
The most common usage of
ln
is the formln -s path/to/source.file path/to/destination.file
. The-s
flag creates a symbolic link, which is more like a redirect to the source, whereas a hard link is a new file sharing the same inodeShow more informationin the file system.By default,
ln
creates a file in the current working directory with the same name as the source. In the example above, we don't provide a destination file name as an argument. This simplifies the command when the link doesn't need a different name.Stage your changes:
git add .
Run
git status
to review your current index, then commit your changes:git commit -m "symlink non-standard files path to wp-content/uploads"
Push the changes to Pantheon:
git push origin master
Your commit can be seen in the Dev environment's commit history. Once this commit is synced to all environments, the plugin will successfully write files within any environment, even when the Dev environment's connection mode is set to Git.
You should not see the newly created files in the Dashboard as "ready to commit," as files are not version controlled. Only the symlink to the new path is in the codebase.
Info:NoteIn our example, we set the target directory of the symlink as
./wp-content/uploads/new-directory
. Make sure this directory is created via SFTP if it does not exist yet.Deploy to Test and confirm results.
Deploy to Live and perform the plugin operation that creates the desired files, then confirm results.
Verify Your Symlink is Correct
You can follow the optional steps below to verify that your symlink is correct.
In the terminal,
cd
to the symlinked path:cd /code/wp-content/cache
Enter
pwd
to confirm you are in the path/files/cache
.If the folder is symlinked correctly, an arrow will be displayed on the left side of the folder that is symlinked in your FTP or SFTP.
If the symlink is incorrect, you will receive an error message.
Click the arrow next to the folder.
If you are directed to the
files/cache
folder, the symlink is correct.
Examples
Divi theme version 4.0.6 and above
As discussed in Modules and Plugins with Known Issues, Divi WordPress Theme & Visual Page Builder version 4.0.6 and above is assumes write access to the codebase where the et-cache
folder is located.
Manually create the target folders wp-content/et-cache
for Dev, Test, Live, and any Multidev environments.
For MacOS & Linux
From the wp-content
directory:
ln -s ./uploads/et-cache ./et-cache
To verify, use ls -al
:
et-cache -> ./uploads/et-cache
For Windows
Note that the syntax for Windows Command Prompt is opposite from MacOS and Linux, requiring the symlink path before the target. From the root of your installation, run mklink
as an admin:
mklink /d .\wp-content\et-cache .\uploads\et-cache
Each command will return the following upon success:
symbolic link created for .\wp-content\et-cache <<===>> .\uploads\et-cache
To verify that you have done it correctly, you should have these when you list your folders in wp-content
directory:
You can also verify success using dir
:
<SYMLINKD> et-cache [.\uploads\et-cache]
Nitropack
As discussed in WordPress Plugins and Themes with Known Issues, Nitropack assumes write access to the wp-content/nitropack
folder and to advanced.cache.php
.
Manually create the target folders code/wp-content/uploads/nitropack
and code/wp-content/uploads/advanced-cache.php
for Dev, Test, and Live environments.
In the command line, navigate to
code/wp-content/uploads
in your Dev environment. Or, if you are using an SFTP client (such as FileZilla), navigate tofiles/
.Create a
nitropack
folder and anadvanced-cache.php
file. Be sure to delete any existingadvanced-cache.php
that is present in the./uploads
directory before creating the file:mkdir ./nitropack && touch ./advanced-cache.php
Repeat steps 1 and 2 for your Test and Live environments.
Navigate back to
code/wp-content
and create a symlink in your Dev environment:ln -s ./uploads/nitropack/ ./nitropack ln -s ./uploads/advanced-cache.php ./advanced-cache.php
Commit changes to the Dev or Multidev environment, then deploy to Test to confirm the results before you deploy to Live.
WP-Rocket
As discussed in WordPress Plugins and Themes with Known Issues, WP-Rocket assumes write access to the codebase.
Manually create the target folders wp-content/uploads/cache
and wp-content/uploads/wp-rocket-config
for Dev, Test, Live, and any Multidev environments.
For MacOS & Linux
From the wp-content
directory:
ln -s ./uploads/cache ./cache
ln -s ./uploads/wp-rocket-config ./wp-rocket-config
To verify, use ls -al
:
cache -> ./uploads/cache
wp-rocket-config -> ./uploads/wp-rocket-config
For Windows
Note that the syntax for Windows is opposite from MacOS and Linux, requiring the symlink path before the target:
mklink /d .\wp-content\cache .\uploads\cache
mklink /d .\wp-content\wp-rocket-config .\uploads\wp-rocket-config
Each command will return the following upon success:
symbolic link created for .\wp-content\cache <<===>> .\uploads\cache
symbolic link created for .\wp-content\wp-rocket-config <<===>> .\uploads\wp-rocket-config
To verify that you have done it correctly, you should have these when you list your folders in wp-content
directory:
You can also verify success using dir
:
<SYMLINKD> cache [.\uploads\cache]
<SYMLINKD> wp-rocket-config [.\uploads\wp-rocket-config]
Uncode Theme
As discussed in WordPress Plugins and Themes with Known Issues, Uncode theme assumes write access to its CSS files and the codebase.
Manually move the target folders. Note that Windows uses
\
instead of/
to separate directories. These examples are formatted or Mac and Linux:wp-content/themes/uncode/core/assets/css
To:
wp-content/uploads/uncode/assets/css
And:
wp-content/themes/uncode/library/css
To:
wp-content/uploads/uncode/library/css
in Dev.Copy the files generated from:
wp-content/themes/uncode/library/css
To:
wp-content/uploads/uncode/library/css
In Test, Live, and any Multidev environments after deploying codes for the theme to take effect in different environments.
For MacOS & Linux
From the wp-content
directory:
ln -s ../../../../uploads/uncode/assets/css ./themes/uncode/core/assets
ln -s ../../../uploads/uncode/library/css ./themes/uncode/library
To verify, use ls -al
in the wp-content/themes/uncode/core/assets
folder:
css -> ../../../../uploads/uncode/assets/css
As well as in the wp-content/themes/uncode/library
folder:
css -> ../../../uploads/uncode/library/css
For Windows
Note that the syntax for Windows is opposite from MacOS and Linux, requiring the symlink path before the target and backslash (\
) is used to denote folders. In the wp-content
folder create the symlinks by:
mklink /d .\themes\uncode\core\assets ..\..\..\..\uploads\uncode\assets\css
mklink /d .\themes\uncode\library ..\..\..\uploads\uncode\library\css
Each command will return the following upon success:
symbolic link created for .\themes\uncode\core\assets <<===>> ..\..\..\..\uploads\uncode\assets\css
symbolic link created for .\themes\uncode\library <<===>> ..\..\..\uploads\uncode\library\css
To verify that you have done it correctly, you should have these when you list your folders in wp-content\themes\uncode\core\assets
directory:
You can also verify success using dir
:
<SYMLINKD> css [..\..\..\..\uploads\uncode\assets\css]
And in the themes\uncode\library
directory:
<SYMLINKD> css [..\..\..\uploads\uncode\library\css]
Troubleshooting
Removing a Symlink
If a site no longer needs a symlink, because you uninstalled the plugin that required it for example, you can simply remove the symlink file from your codebase using rm
. Move back any folders from the public files folder that should be tracked by version control.
Modules That Verify Directories
Some modules and plugins verify that the target directory exists using is_dir()
which returns bool(false) if the directory is a symlink. It may help to patch the module/plugin to use is_link()
instead of is_dir()
.
Incorrect Symlink Paths
If a symlinked folder doesn't show the proper contents, double-check that the path is correct. In Bash, ls -l
will show symlinks paths:
ls -l
lrwxr-xr-x 1 user group 39 Sep 13 14:29 images -> ../plugins/some-plugin/images/
Try changing the working directory in which you create the symlink, using ../
to refer to directories above the working directory, and ./
to refer to the current directory.
More Resources
For more details on creating symbolic links on Mac/Linux, see this thread.