StoutLogic / acf-builder

An Advanced Custom Field Configuration Builder
GNU General Public License v2.0
794 stars 61 forks source link

Support for Polylang's ACF field translations #126

Open adriandmitroca opened 4 years ago

adriandmitroca commented 4 years ago

Hi everyone!

First of all - exceptional work! Working with this package is a true pleasure and improves efficiency a lot!

I've found edge case when working with Polylang Pro though, which probably is really easy to solve.

When you create ACFs through UI, Polylang sets following field attribute by default:

['translations' => 'translate']

for fields that have type:

This can be easily resolved right now by defining extra parameters during field declaration, like this:

$field->addText('Title', ['translations' => 'translate'])

However, by default all text fields are in "Synchronize" mode (when enabled) and so is all fields created through this builder. This means when you make edit within single language, updated value is applied to all other languages as well, which leads to quite unexpected result.

Do you think that support for this should be handled out of the box, behind the scenes, when Polylang plugin is detected?


Documentation for reference: https://polylang.pro/doc/working-with-acf-pro/#customize-acf-fields

besrabasant commented 3 years ago

I am achieving the result using a support class

use Illuminate\Support\Str;
use StoutLogic\AcfBuilder\FieldsBuilder;

abstract class AcfFieldGroup
{
    /** @var FieldsBuilder */
    protected $fieldsBuilder;

    protected $style = "seamless";

    protected $label_placement = "left";

    protected $text_domain;

    /** @var array $translatables */
    protected $translatables = [];

    /** @var string $translatable_prefix */
    protected $translatable_prefix = "acf-field-";

    protected $translations_group;

    abstract public function textDomain(): string;

    abstract public static function slug(): string;

    abstract protected function title(): string;

    abstract protected function configure(FieldsBuilder $fieldsBuilder): void;

    public function translationsGroup()
    {
        return "Default";
    }

    public function __construct()
    {
        $this->setTextDomain($this->textDomain(), $this->translationsGroup());
    }

    public function createFieldsBuilderInstance()
    {
        $this->fieldsBuilder = new FieldsBuilder(static::slug(), [
            'title' => $this->title(),
            'style' => $this->style,
            'label_placement' => $this->label_placement,
            'hide_on_screen' => $this->hideOnScreen(),
        ]);
    }

    /**
     * @param string $text_domain
     * @param string $translations_group
     * @return $this
     */
    private function setTextDomain(string $text_domain, string $translations_group = "Default")
    {
        $this->text_domain = $text_domain;
        $this->translations_group = $translations_group;

        return $this;
    }

    protected function hideOnScreen()
    {
        return [];
    }

    public function registerTranslatable(string $value)
    {
        $value = function_exists('pll__') ? \pll__($value) : $value;

        if (function_exists('pll__')) {
            // I am using Laravel `Str` class to create slug, because I am using Laravel packages in my project. If needed, please use your own implementation to create slug. 
            $this->addTranslatable($this->translatable_prefix . Str::slug($value), $value);
        }

        return __($value, $this->text_domain);
    }

    protected function addTranslatable($key, $value)
    {
        $this->translatables[$key] = $value;

        return $this;
    }

    public function registerTranslatables()
    {
        if (function_exists('pll_register_string')) {
            foreach ($this->translatables as $key => $value) {
                \pll_register_string($key, $value, $this->translations_group);
            }
        }
    }

    public function register()
    {
        \add_action('acf/init', function () {
            $this->createFieldsBuilderInstance();

            $this->configure($this->fieldsBuilder);

            $this->registerTranslatables();

            \acf_add_local_field_group($this->fieldsBuilder->build());
        });
    }
}

and then to add fields


class DemoFieldGroup extends AcfFieldGroup
{
    public function textDomain(): string
    {
        return "my-plugin";
    }

    public function translationsGroup()
    {
        return "my-plugin";
    }

    public static function slug(): string
    {
        return "demo_fields";
    }

    protected function title(): string
    {
        return $this->registerTranslatable("Demo Fields");
    }

    protected function configure(FieldsBuilder $fieldsBuilder): void
    {
        $fieldsBuilder
            ->addImage('demo_text', [
                'label' => $this->registerTranslatable("Demo Text"),
            ])
            ->setLocation('post_type', '==', 'post');
    }

}

(new DemoFieldGroup())->register();