options = $options;
$this->settings = $settings;
$this->isSwitchingVersions = false;
}
// static, as called also in AcfGroup
public static function isAcfProPluginAvailable(): bool
{
return class_exists('acf_pro');
}
public static function getThemeTextDomain(): string
{
return (string)wp_get_theme()->get('TextDomain');
}
public static function getLabelTranslation(string $label, string $textDomain = ''): string
{
$textDomain = $textDomain ?: self::getThemeTextDomain();
// escape quotes to keep compatibility with the generated translation file
// (quotes there escaped to prevent breaking the PHP string)
$label = str_replace("'", "'", $label);
$label = str_replace('"', """, $label);
$translation = __($label, $textDomain);
$translation = str_replace("'", "'", $translation);
$translation = str_replace(""", '"', $translation);
return $translation;
}
protected function amendProFieldLabelAndInstruction(array $field): array
{
$isProField = key_exists('a-pro', $field) &&
$this->isProFieldLocked();
$isAcfProField = !$this->isAcfPluginAvailable(true) &&
key_exists('a-acf-pro', $field);
if (!$isProField &&
!$isAcfProField) {
return $field;
}
$type = $field['type'] ?? '';
$field['label'] = $field['label'] ?? '';
$field['instructions'] = $field['instructions'] ?? '';
if ($isProField) {
if ('tab' === $type) {
$field['label'] = $field['label'] . ' (Pro)';
} else {
$label = !$this->isProVersion() ?
__('Upgrade to Pro', 'acf-views') :
__('Activate your license', 'acf-views');
$link = !$this->isProVersion() ?
Plugin::PRO_VERSION_URL :
$this->getAdminUrl(Dashboard::PAGE_PRO);
$field['instructions'] = sprintf(
'%s %s %s',
$link,
$label,
__('to unlock.', 'acf-views'),
$field['instructions']
);
}
}
if ($isAcfProField) {
$field['instructions'] = sprintf(
'(%s %s) %s',
'https://www.advancedcustomfields.com/pro/',
__('ACF Pro', 'acf-views'),
__('version is required for this feature', 'acf-views'),
$field['instructions']
);
}
return $field;
}
protected function addDeprecatedFieldClass(array $field): array
{
if (!key_exists('a-deprecated', $field)) {
return $field;
}
if (!key_exists('wrapper', $field)) {
$field['wrapper'] = [];
}
if (!key_exists('class', $field['wrapper'])) {
$field['wrapper']['class'] = '';
}
$field['wrapper']['class'] .= ' acf-field--deprecated';
return $field;
}
public function isProFieldLocked(): bool
{
return !$this->isProVersion() ||
!$this->settings->isActiveLicense();
}
public function getName(): string
{
return __('ACF Views Lite', 'acf-views');
}
public function getSlug(): string
{
return $this->slug;
}
public function getShortSlug(): string
{
return $this->shortSlug;
}
public function getVersion(): string
{
// return strval(time());
return $this->version;
}
public function isProVersion(): bool
{
return $this->isProVersion;
}
public function getAssetsUrl(string $file): string
{
return plugin_dir_url(__FILE__) . 'Assets/' . $file;
}
public function getAcfProAssetsUrl(string $file): string
{
return plugin_dir_url(__FILE__) . 'AcfPro/assets/' . $file;
}
public function isAcfPluginAvailable(bool $isProOnly = false): bool
{
// don't use 'is_plugin_active()' as the function available lately
return static::isAcfProPluginAvailable() ||
(!$isProOnly && class_exists('ACF'));
}
public function showWarningAboutInactiveAcfPlugin(): void
{
if ($this->isAcfPluginAvailable()) {
return;
}
$acfPluginInstallLink = get_admin_url(null, static::ACF_INSTALL_URL);
$acfFree = 'https://wordpress.org/plugins/advanced-custom-fields/';
$acfPro = 'https://www.advancedcustomfields.com/pro/';
echo sprintf(
'
',
__('"ACF Views" requires', 'acf-views'),
$acfPluginInstallLink,
__('Advanced Custom Fields', 'acf-views'),
$acfFree,
__('free', 'acf-views'),
__('or', 'acf-views'),
$acfPro,
__('pro', 'acf-views'),
__('to be installed and activated.', 'acf-views'),
);
}
public function showWarningAboutOpcacheIssue(): void
{
if (!function_exists('ini_get') ||
'0' !== ini_get('opcache.save_comments')) {
return;
}
$readMoreLink = sprintf(
'%s',
self::CONFLICTS_URL,
__('Read more', 'acf-views')
);
printf(
'',
__('Compatibility issue detected! "ACF Views" plugin requires "PHPDoc" comments in code.', 'acf-views'),
__(
'Please change the "opcache.save_comments" option in your php.ini file to the default value of "1" on your hosting.',
'acf-views'
),
$readMoreLink
);
}
public function isCPTScreen(string $cptName, array $targetBase = ['post', 'add',]): bool
{
$currentScreen = get_current_screen();
$isTargetPost = in_array($currentScreen->id, [$cptName,], true) ||
in_array($currentScreen->post_type, [$cptName], true);
// base = edit (list management), post (editing), add (adding)
return $isTargetPost &&
in_array($currentScreen->base, $targetBase, true);
}
public function deactivateOtherInstances(string $activatedPlugin): void
{
if (!in_array($activatedPlugin, ['acf-views/acf-views.php', 'acf-views-pro/acf-views-pro.php'], true)) {
return;
}
$pluginToDeactivate = 'acf-views/acf-views.php';
$deactivatedNoticeId = 1;
// If we just activated the free version, deactivate the pro version.
if ($activatedPlugin === $pluginToDeactivate) {
$pluginToDeactivate = 'acf-views-pro/acf-views-pro.php';
$deactivatedNoticeId = 2;
}
if (is_multisite() &&
is_network_admin()) {
$activePlugins = (array)get_site_option('active_sitewide_plugins', []);
$activePlugins = array_keys($activePlugins);
} else {
$activePlugins = (array)get_option('active_plugins', []);
}
foreach ($activePlugins as $pluginBasename) {
if ($pluginToDeactivate !== $pluginBasename) {
continue;
}
$this->options->setTransient(
Options::TRANSIENT_DEACTIVATED_OTHER_INSTANCES,
$deactivatedNoticeId,
1 * HOUR_IN_SECONDS
);
// flag that allows to detect this switching. E.g. Twig won't remove the templates dir
$this->isSwitchingVersions = true;
deactivate_plugins($pluginBasename);
return;
}
}
// notice when either Basic or Pro was automatically deactivated
public function showPluginDeactivatedNotice(): void
{
$deactivatedNoticeId = (int)$this->options->getTransient(Options::TRANSIENT_DEACTIVATED_OTHER_INSTANCES);
// not set = false = 0
if (!in_array($deactivatedNoticeId, [1, 2,], true)) {
return;
}
$message = sprintf(
'%s "%s".',
__(
"'ACF Views Lite' and 'ACF Views Pro' should not be active at the same time. We've automatically deactivated",
'acf-views'
),
1 === $deactivatedNoticeId ?
__('ACF Views Lite', 'acf-views') :
__('ACF Views Pro', 'acf-views')
);
$this->options->deleteTransient(Options::TRANSIENT_DEACTIVATED_OTHER_INSTANCES);
echo sprintf(
'',
$message
);
}
public function amendFieldSettings(array $field): array
{
$field = $this->amendProFieldLabelAndInstruction($field);
$field = $this->addDeprecatedFieldClass($field);
return $field;
}
public function addClassToAdminProFieldClasses(array $wrapper, array $field): array
{
$isProField = key_exists('a-pro', $field) &&
$this->isProFieldLocked();
$isAcfProField = !$this->isAcfPluginAvailable(true) &&
key_exists('a-acf-pro', $field);
if (!$isProField &&
!$isAcfProField) {
return $wrapper;
}
if (!key_exists('class', $wrapper)) {
$wrapper['class'] = '';
}
$wrapper['class'] .= ' acf-views-pro';
return $wrapper;
}
public function getAdminUrl(
string $page = '',
string $cptName = ViewsCpt::NAME,
string $base = 'edit.php'
): string {
$pageArg = $page ?
'&page=' . $page :
'';
// don't use just '/wp-admin/x' as some websites can have custom admin url, like 'wp.org/wordpress/wp-admin'
$pageUrl = get_admin_url(null, $base . '?post_type=');
return $pageUrl . $cptName . $pageArg;
}
public function isSwitchingVersions(): bool
{
return $this->isSwitchingVersions;
}
// for some reason, ACF ajax form validation doesn't work on the wordpress.com hosting. So need to use a special approach
public function isWordpressComHosting(): bool
{
return defined('WPCOMSH_VERSION') ||
defined('WPCOM_CORE_ATOMIC_PLUGINS');
}
public function setHooks(bool $isAdmin): void
{
if (!$isAdmin) {
return;
}
add_action('admin_notices', [$this, 'showWarningAboutInactiveAcfPlugin']);
add_action('admin_notices', [$this, 'showWarningAboutOpcacheIssue']);
add_action('activated_plugin', [$this, 'deactivateOtherInstances']);
add_action('pre_current_active_plugins', [$this, 'showPluginDeactivatedNotice']);
add_filter('acf/prepare_field', [$this, 'amendFieldSettings']);
add_filter('acf/field_wrapper_attributes', [$this, 'addClassToAdminProFieldClasses'], 10, 2);
}
}