You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

616 lines
19 KiB

<?php
/**
* Plugin Name: Meta Field Block
* Plugin URI: https://metafieldblock.com?utm_source=MFB&utm_campaign=MFB+visit+site&utm_medium=link&utm_content=Plugin+URI
* Description: Display a meta field or a custom field as a block on the front end, supporting ACF fields.
* Requires at least: 6.3
* Requires PHP: 7.4
* Version: 1.2.5
* Author: Phi Phan
* Author URI: https://metafieldblock.com?utm_source=MFB&utm_campaign=MFB+visit+site&utm_medium=link&utm_content=Author+URI
*
* @package MetaFieldBlock
* @copyright Copyright(c) 2022, Phi Phan
*
*/
namespace MetaFieldBlock;
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;
if ( function_exists( __NAMESPACE__ . '\\mfb_fs' ) ) {
mfb_fs()->set_basename( false, __FILE__ );
return;
}
// Include Freemius functions.
require_once dirname( __FILE__ ) . '/freemius.php';
if ( !class_exists( MetaFieldBlock::class ) ) {
/**
* The main class
*/
class MetaFieldBlock
{
/**
* Plugin version
*
* @var String
*/
protected $version = '1.2.5' ;
/**
* Components
*
* @var Array
*/
protected $components = array() ;
/**
* Plugin instance
*
* @var MetaFieldBlock
*/
private static $instance ;
/**
* A dummy constructor
*/
private function __construct()
{
}
/**
* Initialize the instance.
*
* @return MetaFieldBlock
*/
public static function get_instance()
{
if ( !isset( self::$instance ) ) {
self::$instance = new MetaFieldBlock();
self::$instance->initialize();
}
return self::$instance;
}
/**
* Kick start function.
* Define constants
* Load dependencies
* Register components
* Run the main hooks
*
* @return void
*/
public function initialize()
{
// Setup constants.
$this->setup_constants();
// Load dependencies.
$this->load_dependencies();
// Register components.
$this->register_components();
// Run hooks.
$this->run();
}
/**
* Setup constants
*
* @return void
*/
public function setup_constants()
{
$this->define_constant( 'MFB', true );
$this->define_constant( 'MFB_ROOT_FILE', __FILE__ );
$this->define_constant( 'MFB_VERSION', $this->version );
$this->define_constant( 'MFB_PATH', trailingslashit( plugin_dir_path( MFB_ROOT_FILE ) ) );
$this->define_constant( 'MFB_URL', trailingslashit( plugin_dir_url( MFB_ROOT_FILE ) ) );
}
/**
* Load core components
*
* @return void
*/
public function register_components()
{
// Load & register core components.
$this->include_file( 'includes/rest-fields.php' );
$this->include_file( 'includes/acf-fields.php' );
$this->include_file( 'includes/dynamic-field.php' );
$this->include_file( 'includes/freemius-config.php' );
$this->include_file( 'includes/settings.php' );
$core_components = [
RestFields::class,
ACFFields::class,
DynamicField::class,
Settings::class,
FreemiusConfig::class
];
$components = apply_filters( 'meta_field_block_get_components', $core_components );
foreach ( $components as $component ) {
$this->register_component( $component );
}
}
/**
* Load dependencies
*
* @return void
*/
public function load_dependencies()
{
// Load core component.
$this->include_file( 'includes/core-component.php' );
$this->include_file( 'includes/helper-functions.php' );
}
/**
* Run main hooks
*
* @return void
*/
public function run()
{
// Load translations.
add_action( 'plugins_loaded', [ $this, 'load_textdomain' ] );
// Register the block.
add_action( 'init', [ $this, 'register_block' ] );
// Save version and trigger upgraded hook.
add_action( 'admin_menu', [ $this, 'version_upgrade' ], 1 );
// Run all components.
foreach ( $this->components as $component ) {
$component->run();
}
}
/**
* Load text domain
*
* @return void
*/
public function load_textdomain()
{
load_plugin_textdomain( 'display-a-meta-field-as-block', false, plugin_basename( realpath( __DIR__ . '/languages' ) ) );
}
/**
* Register the block
*
* @return void
*/
public function register_block()
{
// Register block.
register_block_type( MFB_PATH . '/build', [
'render_callback' => [ $this, 'render_block' ],
'skip_inner_blocks' => true,
] );
}
/**
* Renders the `mbf/meta-field-block` block on the server.
*
* @param array $attributes Block attributes.
* @param string $content Block default content.
* @param WP_Block $block Block instance.
* @return string Returns the value for the field.
*/
public function render_block( $attributes, $content, $block )
{
$field_name = $attributes['fieldName'] ?? '';
if ( empty($field_name) ) {
return '';
}
// Get object type.
$object_type = $this->get_object_type( $field_name, $attributes, $block );
// Get object id.
$object_id = $this->get_object_id( $object_type, $attributes, $block );
// Get field type.
$field_type = $attributes['fieldType'] ?? 'rest_field';
// Is dynamic block?
$is_dynamic_block = $this->is_dynamic_block( $attributes );
if ( $is_dynamic_block ) {
if ( 'acf' === $field_type ) {
if ( function_exists( 'get_field_object' ) ) {
$block_value = $this->get_component( ACFFields::class )->get_field_value( $field_name, $object_id, $object_type );
$content = $block_value['value'] ?? '';
$content = apply_filters(
'_meta_field_block_render_dynamic_block',
$content,
$block_value,
$object_id,
$object_type,
$attributes,
$block
);
} else {
$content = '<code><em>' . __( 'This data type requires the ACF plugin installed and activated!', 'display-a-meta-field-as-block' ) . '</em></code>';
}
} else {
if ( in_array( $object_type, [ 'post', 'term', 'user' ], true ) ) {
$get_meta_callback = "get_{$object_type}_meta";
$content = $get_meta_callback( $object_id, $field_name, true );
} else {
$content = apply_filters(
'_meta_field_block_get_field_value_other_type',
$content,
$field_name,
$object_id,
$object_type,
$attributes,
$block
);
}
$content = apply_filters(
'_meta_field_block_get_field_value',
$content,
$field_name,
$object_id,
$object_type,
$attributes,
$block
);
}
} else {
$content = apply_filters(
'_meta_field_block_render_static_block',
$content,
$field_name,
$object_id,
$object_type,
$attributes,
$block
);
}
// Additional block classes.
$classes = "is-{$field_type}-field";
if ( $attributes['fieldSettings']['type'] ?? false ) {
$classes .= " is-{$attributes['fieldSettings']['type']}-field";
}
// Get the block markup.
return meta_field_block_get_block_markup(
$content,
$attributes,
$block,
$object_id,
$object_type,
$classes,
$is_dynamic_block
);
}
/**
* Get object type.
*
* @param string $field_name Field name.
* @param array $attributes Block attributes.
* @param WP_Block $block The block instance.
* @return string
*/
public function get_object_type( $field_name, $attributes, $block )
{
// Get object type from meta type.
$object_type = $attributes['metaType'] ?? '';
if ( $object_type ) {
return $object_type;
}
// Cache key.
$cache_key = 'object_type_' . $field_name;
// Get object_type from the cache.
$object_type = wp_cache_get( $cache_key, 'mfb' );
if ( $object_type === false ) {
$object_type = 'post';
if ( $this->is_custom_context( $field_name, $block, is_category() || is_tag() || is_tax() ) ) {
$object_type = 'term';
} elseif ( $this->is_custom_context( $field_name, $block, is_author() ) ) {
$object_type = 'user';
}
// Update cache.
if ( !empty($object_type) ) {
wp_cache_set( $cache_key, $object_type, 'mfb' );
}
}
return $object_type;
}
/**
* Get object id by object type.
*
* @param string $object_type Object type.
* @param array $attributes Block attributes.
* @param WP_Block $block Block instance.
*
* @return string
*/
public function get_object_id( $object_type, $attributes, $block )
{
if ( in_array( $object_type, [ 'post', 'term', 'user' ], true ) && ($attributes['isCustomSource'] ?? false) && ($attributes['objectId'] ?? false) ) {
return $attributes['objectId'];
}
if ( in_array( $object_type, [ 'term', 'user' ], true ) ) {
// Get queried object id.
$object_id = get_queried_object_id();
} else {
if ( isset( $block->context['postId'] ) ) {
// Get value from the context.
$object_id = $block->context['postId'];
} else {
// Fallback to the current queried object id.
$object_id = get_queried_object_id();
}
}
return $object_id;
}
/**
* Is the field is in a custom context?
*
* @param string $field_name
* @param WP_Block $block
* @param boolean $condition
* @return boolean
*/
private function is_custom_context( $field_name, $block, $condition )
{
if ( $condition ) {
if ( !isset( $block->context['postId'] ) ) {
return true;
} else {
global $_wp_current_template_id, $_wp_current_template_content ;
if ( !$_wp_current_template_id || !$_wp_current_template_content ) {
return false;
} else {
// Cache key for the blocks of template.
$cache_key = 'blocks_by_' . str_replace( '//', '__', $_wp_current_template_id );
// Get from the cache.
$blocks = wp_cache_get( $cache_key, 'mfb' );
if ( $blocks === false ) {
$blocks = \parse_blocks( $_wp_current_template_content );
// Update cache.
if ( !empty($blocks) ) {
wp_cache_set( $cache_key, $blocks, 'mfb' );
}
}
return $this->find_mfb( $field_name, $blocks );
}
}
}
return false;
}
/**
* Find MFB not within a core query from an array of blocks
*
* @param string $field_name
* @param array $blocks
* @return boolean
*/
private function find_mfb( $field_name, $blocks )
{
$found = false;
foreach ( $blocks as $block ) {
$block_name = $block['blockName'] ?? '';
if ( 'core/query' === $block_name ) {
continue;
}
if ( 'mfb/meta-field-block' === $block_name ) {
if ( $field_name === ($block['attrs']['fieldName'] ?? '') ) {
$found = true;
break;
}
} elseif ( !empty($block['innerBlocks']) ) {
$found = $this->find_mfb( $field_name, $block['innerBlocks'] );
if ( $found ) {
break;
}
}
}
return $found;
}
/**
* Check whether if the block is dynamic of static
*
* @param array $attributes
* @param mixed $content
* @param WP_Block $block
* @return boolean
*/
private function is_dynamic_block( $attributes )
{
$field_type = $attributes['fieldType'] ?? '';
if ( 'acf' === $field_type ) {
if ( $attributes['fieldSettings']['isStatic'] ?? false ) {
return false;
}
}
return true;
}
/**
* Save version and trigger an upgrade hook
*
* @return void
*/
public function version_upgrade()
{
if ( get_option( 'mfb_current_version' ) !== $this->version ) {
do_action( 'mfb_version_upgraded', get_option( 'mfb_current_version' ), $this->version );
update_option( 'mfb_current_version', $this->version );
}
}
/**
* Register component
*
* @param string $classname The class name of the component.
* @return void
*/
public function register_component( $classname )
{
$this->components[$classname] = new $classname( $this );
}
/**
* Get a component by class name
*
* @param string $classname The class name of the component.
* @return mixed
*/
public function get_component( $classname )
{
return $this->components[$classname] ?? false;
}
/**
* Define constant
*
* @param string $name The name of the constant.
* @param mixed $value The value of the constant.
* @return void
*/
public function define_constant( $name, $value )
{
if ( !defined( $name ) ) {
define( $name, $value );
}
}
/**
* Retrn file path for file or folder.
*
* @param string $path file path.
* @return string
*/
public function get_file_path( $path )
{
return MFB_PATH . $path;
}
/**
* Include file path.
*
* @param string $path file path.
* @return mixed
*/
public function include_file( $path )
{
return include_once $this->get_file_path( $path );
}
/**
* Get file uri by file path.
*
* @param string $path file path.
* @return string
*/
public function get_file_uri( $path )
{
return MFB_URL . $path;
}
/**
* Create version for scripts/styles
*
* @param array $asset_file
* @return string
*/
public function get_script_version( $asset_file )
{
return ( wp_get_environment_type() !== 'production' ? $asset_file['version'] ?? MFB_VERSION : MFB_VERSION );
}
/**
* Get the plugin version
*
* @return string
*/
public function get_plugin_version()
{
return $this->version;
}
/**
* Is Debugging
*
* @return boolean
*/
public function is_debug_mode()
{
return defined( 'MFB_DEBUG' ) && MFB_DEBUG || 'development' === wp_get_environment_type();
}
/**
* Enqueue debug log information
*
* @param string $handle
* @return void
*/
public function enqueue_debug_information( $handle )
{
wp_add_inline_script( $handle, 'var MFBLOG=' . wp_json_encode( [
'environmentType' => ( $this->is_debug_mode() ? 'development' : wp_get_environment_type() ),
] ), 'before' );
}
}
/**
* Kick start
*
* @return MetaFieldBlock instance
*/
function mfb_get_instance()
{
return MetaFieldBlock::get_instance();
}
// Instantiate.
mfb_get_instance();
}
if ( !function_exists( __NAMESPACE__ . '\\meta_field_block_activate' ) ) {
/**
* Trigger an action when the plugin is activated.
*
* @return void
*/
function meta_field_block_activate()
{
do_action( 'meta_field_block_activate' );
}
register_activation_hook( __FILE__, __NAMESPACE__ . '\\meta_field_block_activate' );
}