Adding wp language files on deploy

There you go:

Let me know if it works for you (and if not).

3 Likes

It can be more simple.

In finalize-after hook add at the end of block:

  - name: Install WP language es_ES
    command: wp core language install es_ES --activate
    args:
      chdir: "{{ deploy_helper.current_path }}"

  - name: Update active language
    command: wp core language update
    args:
      chdir: "{{ deploy_helper.current_path }}"

And in roles/deploy/defaults/main.yml:

project_shared_children:
  - path: web/app/uploads
    src: uploads
  - path: web/app/languages
    src: languages

Sharing languages folder the install only work on first deploy and on successive deploys is skipped (by wp-cli).
The second task update (currently active) language for updated core/themes/plugins.

2 Likes

Sure, I had something like this as well, but I don’t want this hard-coded into the hook, prefer to have it configurable as a list in wordpress_sites.

Didn’t know this, but makes sense. It puts out a warning, though. It’s no big deal to check for the existance of the po-file, also taught me some Ansible syntax :slight_smile:

What ansible code can be added to avoid the warning?

You can have deploy hooks per site:

In ‘roles/deploy/defaults/main.yml’:

deploy_finalize_after:
  - "{{ playbook_dir }}/roles/deploy/hooks/finalize-after.yml" # built-in
  - "{{ playbook_dir }}/deploy-hooks/sites/{{ site }}-finalize-after.yml"

Then as shown by pacotole further above in this thread,
e.g. for site example.com in ‘deploy-hooks/sites/example.com-finalize-after.yml’:

  - name: Finish WP installation (required for installing languages on initial deploy)
    command: wp core install --skip-email --url=www.example.com --title="The WordPress site" --admin_user=theuser --admin_password="the password" --admin_email=info@example.com
    args:
      chdir: "{{ deploy_helper.current_path }}"

  - name: Install WP language es_ES
    command: wp core language install es_ES --activate
    args:
      chdir: "{{ deploy_helper.current_path }}"

  - name: Update active language
    command: wp core language update
    args:
      chdir: "{{ deploy_helper.current_path }}"

Edit: I had an error when deploying the first time (to a fresh staging system). The reason was that the WordPress installation has to be finished. I added a wp cli command for this before the command for installing the languages (wp core install --[...]) (wp core is idempotent, it won’t reconfigure an existing configured WordPress installation).

2 Likes

Updated approach:


Ensure finished WordPress setup and installing additonal languages in finalize-after site hook:
In case of formal variant languages it can be helpful to also install the non-formal language as a fallback because plugins can be disproportionally translated for the non-formal variant.

- name: Install WP (required for installing languages on non-transferred site)
  command: wp core {{ project.multisite.enabled | default(false) | ternary('multisite-install', 'install') }}
           --allow-root
           --url="{{ site_env.wp_home }}"
           {% if project.multisite.enabled | default(false) %}
           --base="{{ project.multisite.base_path | default('/') }}"
           --subdomains="{{ project.multisite.subdomains | default('false') }}"
           {% endif %}
           --title="{{ project.site_title | default(site) }}"
           --admin_user="{{ project.admin_user | default('admin') }}"
           --admin_password="{{ vault_wordpress_sites[site].admin_password }}"
           --admin_email="{{ project.admin_email }}"
  args:
    chdir: "{{ deploy_helper.current_path }}"
  register: wp_install
  changed_when: "'WordPress is already installed.' not in wp_install.stdout and 'The network already exists.' not in wp_install.stdout"


  - name: Install WP language de_DE
  command: wp core language install de_DE
  args:
    chdir: "{{ deploy_helper.current_path }}"

- name: Install WP language de_DE_formal
  command: wp core language install de_DE_formal --activate
  args:
    chdir: "{{ deploy_helper.current_path }}"


- name: Update active language
  command: wp core language update
  args:
    chdir: "{{ deploy_helper.current_path }}"

The username / password for WordPress setup can reflect the real credentials (before transferring the database to system, e.g. using a plugin instead, which in turn requires an admin login) are stored in vault.yml which should be the correct place for secrets:

# Variables to accompany `group_vars/production/wordpress_sites.yml`
# Note: the site name (`example.com`) must match up with the site name in the above file.
vault_wordpress_sites:
  example.com:
    env:
      db_password: "example_dbpassword"
      # Generate your keys here: https://roots.io/salts.html
      auth_key: "generateme"
      secure_auth_key: "generateme"
      logged_in_key: "generateme"
      nonce_key: "generateme"
      auth_salt: "generateme"
      secure_auth_salt: "generateme"
      logged_in_salt: "generateme"
      nonce_salt: "generateme"
    admin_user: "wordpress-admin-username"
    admin_password: "wordpress-admin-password"

And finally for speeding up and preventing gaps of missing language for longer duration during deploy:
roles/deploy/defaults/main.yml (at line 14):

# There are certain folders you'll want to copy from release to release to speed up deploys.
# Examples: Composer's `vendor` folder, npm's `node_modules`.
# These should not be part of project_shared_children since dependencies need to be atomic and tied to a deploy.
project_copy_folders:
  - vendor
  - web/app/languages
1 Like

I came across this thread and remembered I’d solved this problem last year, when I was tweaking the script to set the default language and site tagline (both come from groups_vars/<env>/wordpress_sites.yml).

Here’s my solution, which is in roles/wordpress-install/tasks/main.yml:

- name: Install WP Site Language
  command: wp core language install "{{ item.value.site_language }}" --allow-root
  args:
    chdir: "{{ www_root }}/{{ item.key }}/{{ item.value.current_path | default('current') }}/"
  with_dict: "{{ wordpress_sites }}"
  when:
    - item.value.site_language | default(false)
    - wp_install.changed

- name: Activate WP Site Language
  command: wp core language activate "{{ item.value.site_language }}" --allow-root
  args:
    chdir: "{{ www_root }}/{{ item.key }}/{{ item.value.current_path | default('current') }}/"
  with_dict: "{{ wordpress_sites }}"
  when:
    - item.value.site_language | default(false)
    - "'{{ item.value.site_language }}' in wp_install.results[0].item.value.site_language"

- name: Update WP Tagline
  command: wp option update blogdescription "{{ item.value.site_tagline }}" --allow-root
  args:
    chdir: "{{ www_root }}/{{ item.key }}/{{ item.value.current_path | default('current') }}/"
  with_dict: "{{ wordpress_sites }}"
  when:
    - item.value.site_tagline | default(false)
    - wp_install.changed
1 Like

When having multiple sites it may be cleaner and less error-prone to ensure that the WordPress sites are installed in a general finalize-after deploy hook,
deploy-hooks/finalize-after.yml:

- name: Install WP (required for installing languages on non-transferred site)
  command: wp core {{ project.multisite.enabled | default(false) | ternary('multisite-install', 'install') }}
           --allow-root
           --url="{{ site_env.wp_home }}"
           {% if project.multisite.enabled | default(false) %}
           --base="{{ project.multisite.base_path | default('/') }}"
           --subdomains="{{ project.multisite.subdomains | default('false') }}"
           {% endif %}
           --title="{{ project.site_title | default(site) }}"
           --admin_user="{{ project.admin_user | default('admin') }}"
           --admin_password="{{ vault_wordpress_sites[site].admin_password }}"
           --admin_email="{{ project.admin_email }}"
  args:
    chdir: "{{ deploy_helper.current_path }}"
  register: wp_install
  changed_when: "'WordPress is already installed.' not in wp_install.stdout and 'The network already exists.' not in wp_install.stdout"

Makes sense to me. Maybe add an option for this under wordpress_sites? Development has an option site_install for this. Could that be used for deploy as well?

This would be a nice additon.
When I recall correctly, this config had been even taken from the dev playbook:


and

So the wordpress-install task could be just included in normal deploy task which would reduce code duplication.

@strarsis: I just tried adding - web/app/languages to project_copy_folders and the languages folder was copied to the root (where vendor is copied as well) after the deploy. Did that work differently for you?
The command is cp -rp {{ deploy_helper.current_path }}/{{ item.item }} {{ deploy_helper.new_release_path }} which would just do that.
Maybe it should be changed to cp -rp {{ deploy_helper.current_path }}/{{ item.item }} {{ deploy_helper.new_release_path }}/{{ item.item }}?

Generally, copying items to be “cached” is more efficient compared to just share the language files over releases as tnere may also be issues with language files one would want to rollback as release, so I agree with that using the copy option is better than the shared option. I need to try this on a test system to reproduce the issue.

I totally agree that this is the better option for language files, when they are managed fom ansible. The shared folders should be used for files that are changed from wordpress.
My “fix”:
cp -rp {{ deploy_helper.current_path }}/{{ item.item }} {{ deploy_helper.new_release_path }}/{{ item.item }}
worked for me BTW. Although I wonder why copy or synchronize ansible modules are not used here. The “fix” doesn’t work i.e. when the languages folder already exists, then you get:
/languages/languages

1 Like

Would replacing the code to use the copy or synchronize
ansible modules be worth a pull request in Trellis?
This would improve the code and fix the additional issues.

Generally synchronize should be a better fit for copying a directory of unknown complexity. But I’m no ansible expert. And I don’t know why cp -rp was used here…

1 Like

Would anyone be so kind to provide a step by step? I’ve kinda got it working right now.

I have a share-after.yml hook that install the languages defined in wordpress_sites.yml. I believe this is a solution provided by @mockey. This generates an error on first deploy so I comment out:

deploy_share_after:

  • “{{ playbook_dir }}/deploy-hooks/share-after.yml”

in /roles/deploy/defaults/main.yml

and then run a second deploy with that line active.

Yes, there are lots of different config spread around some threads now.
Like a wiki page for best practices for installing languages on a bedrock/trellis site.

Maybe i can simply add a check if wordpress is installed to avoid the error on the first deploy. I’ll try to update my gist next week. Some methods have changed in wp-cli as well.

PR for wiki page:

Thank you @strarsis :pray: This is now published at:

2 Likes