HEX
Server: Apache/2.4.65 (Debian)
System: Linux 88f31f35b0b8 6.1.0-38-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.147-1 (2025-08-02) x86_64
User: www-data (33)
PHP: 8.2.29
Disabled: NONE
Upload Files
File: /var/www/html/wp-content/plugins/advanced-post-manager/tribe-apm.php
<?php
/**
 * Plugin Name: Advanced Post Manager
 * Description: Dialing custom post types to 11 with advanced filtering controls.
 * Version: 4.5.5
 * Requires at least: 6.6
 * Requires PHP: 7.4
 * Author: The Events Calendar
 * Author URI: https://evnt.is/4n
 * Text Domain: advanced-post-manager
 * License: GPLv2 or later
 * Elementor tested up to: 3.23.1
 * Elementor Pro tested up to: 3.23.0
 */

define( 'TRIBE_APM_PATH', plugin_dir_path( __FILE__ ) );
define( 'TRIBE_APM_FILE', __FILE__ );
define( 'TRIBE_APM_LIB_PATH', TRIBE_APM_PATH . 'lib/' );

// Load the required php min version functions.
require_once TRIBE_APM_LIB_PATH . 'php-min-version.php';

/**
 * Verifies if we need to warn the user about min PHP version and bail to avoid fatals.
 */
if ( tribe_is_not_min_php_version() ) {
	tribe_not_php_version_textdomain( 'advanced-post-manager', TRIBE_APM_FILE );
	/**
	 * Include the plugin name into the correct place.
	 *
	 * @since 4.5.5
	 *
	 * @param array $names current list of names.
	 *
	 * @return array
	 */
	function tribe_apm_not_php_version_plugin_name( $names ) {
		$names['tribe-apm'] = esc_html__( 'Advanced Post Manager', 'advanced-post-manager' );
		return $names;
	}
	add_filter( 'tribe_not_php_version_names', 'tribe_apm_not_php_version_plugin_name' );

	if ( ! has_filter( 'admin_notices', 'tribe_not_php_version_notice' ) ) {
		add_action( 'admin_notices', 'tribe_not_php_version_notice' );
	}

	return false;
}

// phpcs:disable Universal.Files.SeparateFunctionsFromOO.Mixed
/**
 * A class to manage the plugin.
 */
class Tribe_APM {
	/**
	 * The current version of APM.
	 */
	const VERSION = '4.5.5';

	/**
	 * The textdomain for the plugin.
	 *
	 * @var string
	 */
	protected $textdomain = 'advanced-post-manager';

	/**
	 * The arguments for the plugin.
	 *
	 * @var array
	 */
	protected $args;

	/**
	 * The metaboxes for the plugin.
	 *
	 * @var array
	 */
	protected $metaboxes;

	/**
	 * The URL for the plugin.
	 *
	 * @var string
	 */
	protected $url;

	/**
	 * The columns for the plugin.
	 * Holds a Tribe_Columns object.
	 *
	 * @var Tribe_Columns
	 */
	public $columns;

	/**
	 * The filters for the plugin.
	 * Holds a Tribe_Filters object.
	 *
	 * @var Tribe_Filters
	 */
	public $filters;

	/**
	 * The post type for the plugin.
	 *
	 * @var string
	 */
	public $post_type;

	/**
	 * Automatically add filters/cols for registered taxonomies?
	 *
	 * @var bool
	 */
	public $add_taxonomies = true;

	/**
	 * Show export button? (Currently does nothing)
	 *
	 * @var bool
	 */
	public $export = false;

	/**
	 * Show metaboxes?
	 *
	 * @var bool
	 */
	public $do_metaboxes = true;

	/**
	 * Whether we're in a delayed initialization.
	 *
	 * @var bool
	 */
	public static $delayed_init = false;

	// CONSTRUCTOR.

	/**
	 * Kicks things off
	 *
	 * @param string $post_type What post_type to enable filters for.
	 * @param array  $args      Multidimensional array of filter/column arrays. See documentation.
	 * @param array  $metaboxes The metaboxes to use.
	 */
	public function __construct( $post_type, $args, $metaboxes = [] ) {
		$this->post_type = $post_type;
		$this->args      = $args;
		$this->metaboxes = $metaboxes;

		$this->textdomain = apply_filters( 'tribe_apm_textdomain', $this->textdomain );
		$this->url        = apply_filters( 'tribe_apm_url', plugins_url( '', __FILE__ ), __FILE__ );

		$this->register_active_plugin();
		$this->register_hooks();

		// Check if we need to delay initialization for screen availability.
		if ( ! is_admin() ) {
			// Not admin, bail.
			return;
		} elseif ( ! wp_doing_ajax() && ! get_current_screen() ) {
			// Screen not available yet, delay until current_screen.
			self::$delayed_init = true;
			add_action( 'current_screen', [ $this, 'delayed_init' ] );
		} else {
			// Screen available or not needed, initialize normally.
			self::$delayed_init = false;
			add_action( 'admin_init', [ $this, 'init' ], 0 );
		}
	}

	// PUBLIC METHODS.

	/**
	 * Register hooks that don't depend on initialization state.
	 *
	 * @since 4.5.5
	 */
	private function register_hooks() {
		// Always-available filter for resource URLs.
		add_filter( 'tribe_apm_resources_url', [ $this, 'resources_url' ] );
	}

	/**
	 * Registers this plugin as being active for other tribe plugins and extensions.
	 *
	 * @return bool Indicates if Tribe Common wants the plugin to run.
	 */
	public function register_active_plugin() {
		if ( ! function_exists( 'tribe_register_plugin' ) ) {
			return true;
		}

		return tribe_register_plugin( TRIBE_APM_FILE, __CLASS__, self::VERSION );
	}

	/**
	 * Add some additional filters/columns.
	 *
	 * @param array $filters Multidimensional array of filter/column arrays.
	 */
	public function add_filters( $filters = [] ) {
		if ( empty( $filters ) ) {
			return;
		}

		if ( ! is_array( $filters ) ) {
			return;
		}

		$this->args = array_merge( $this->args, $filters );
	}

	// CALLBACKS.

	/**
	 * Initialize the filters and columns.
	 */
	public function init() {
		if ( ! $this->is_active() ) {
			return;
		}

		$hook = self::$delayed_init ? 'current_screen' : 'admin_init';

		$this->load_text_domain();

		// Register hooks that depend on successful initialization.
		add_action( $hook, [ $this, 'init_meta_box' ] );
		add_action( 'tribe_cpt_filters_init', [ $this, 'maybe_add_taxonomies' ], 10, 1 );

		do_action( 'tribe_cpt_filters_init', $this );

		require_once TRIBE_APM_LIB_PATH . 'tribe-filters.class.php';
		require_once TRIBE_APM_LIB_PATH . 'tribe-columns.class.php';
		$this->filters = new Tribe_Filters( $this->post_type, $this->get_filter_args() );
		$this->columns = new Tribe_Columns( $this->post_type, $this->get_column_args() );

		do_action( 'tribe_cpt_filters_after_init', $this );

		add_action( 'admin_notices', [ $this, 'maybe_show_filters' ] );
		add_action( 'admin_enqueue_scripts', [ $this, 'maybe_enqueue' ] );
	}

	/**
	 * Delayed initialization when screen is available.
	 *
	 * This method is called when get_current_screen() is not available during admin_init,
	 * which can happen in newer versions of The Events Calendar (6.12.0+).
	 *
	 * @since 4.5.4
	 */
	public function delayed_init() {
		// Remove the hook immediately to prevent multiple calls.
		remove_action( 'current_screen', [ $this, 'delayed_init' ] );

		// Only initialize if we haven't already and we're on the right screen.
		if ( ! $this->is_active() ) {
			return;
		}

		// Check if already initialized (filters/columns objects exist).
		if ( isset( $this->filters ) && isset( $this->columns ) ) {
			return;
		}

		$this->init( true );
	}

	/**
	 * Load the text domain.
	 *
	 * @return void
	 */
	private function load_text_domain() {
		load_plugin_textdomain( 'advanced-post-manager', false, dirname( plugin_basename( __FILE__ ) ) . '/lang' );
	}

	/**
	 * Get the resources URL.
	 *
	 * @since 4.5.5 Remove unused parameter.
	 *
	 * @return string The resources URL.
	 */
	public function resources_url() {
		return trailingslashit( $this->url ) . 'resources/';
	}

	/**
	 * Initialize the meta box.
	 *
	 * @return void
	 */
	public function init_meta_box() {
		if ( ! $this->do_metaboxes ) {
			return;
		}

		require_once TRIBE_APM_LIB_PATH . 'tribe-meta-box-helper.php';
		$for_meta_box = $this->only_meta_filters( $this->args, 'metabox' );
		new Tribe_Meta_Box_Helper( $this->post_type, $for_meta_box, $this->metaboxes );
	}

	/**
	 * Maybe add taxonomies.
	 *
	 * Dogfooding a bit! We're hooked into the tribe_cpt_filters_init action hook.
	 *
	 * @param Tribe_APM $tribe_apm The Tribe_APM object.
	 *
	 * @return void
	 */
	public function maybe_add_taxonomies( $tribe_apm ) {
		if ( ! $tribe_apm->add_taxonomies ) {
			return;
		}

		$args       = [];
		$taxonomies = apply_filters( 'tribe_apm_taxonomies', get_taxonomies( [], 'objects' ), $this->post_type );
		foreach ( $taxonomies as $tax ) {
			if ( $tax->show_ui && in_array( $tribe_apm->post_type, (array) $tax->object_type, true ) ) {
				$args[ 'taxonomy-' . $tax->name ] = [
					'name'       => $tax->labels->name,
					'taxonomy'   => $tax->name,
					'query_type' => 'taxonomy',
				];
			}
		}

		$tribe_apm->add_filters( $args );
	}

	/**
	 * Maybe enqueue the scripts and styles.
	 *
	 * @since 4.5.5 Remove unused parameter.
	 *
	 * @return void
	 */
	public function maybe_enqueue() {
		if ( ! $this->is_active() ) {
			return;
		}

		wp_enqueue_script(
			'tribe-fac',
			$this->url . '/resources/tribe-apm.js',
			[ 'jquery' ],
			self::VERSION,
			true
		);

		wp_enqueue_style(
			'tribe-fac',
			$this->url . '/resources/tribe-apm.css',
			[],
			self::VERSION,
			'all'
		);
	}

	/**
	 * Maybe show the filters.
	 *
	 * @return void
	 */
	public function maybe_show_filters() {
		if ( ! $this->is_active() ) {
			return;
		}

		require_once 'views/edit-filters.php';
	}

	// UTILITIES AND INTERNAL METHODS.

	/**
	 * Get the filter arguments.
	 *
	 * @return array The filter arguments.
	 */
	protected function get_filter_args() {
		return $this->filter_disabled( $this->args, 'filters' );
	}

	/**
	 * Get the column arguments.
	 *
	 * @return array The column arguments.
	 */
	protected function get_column_args() {
		return $this->filter_disabled( $this->args, 'columns' );
	}

	/**
	 * Filter out an array of args where children arrays have a disable key set to $type.
	 *
	 * @param array        $args Multidimensional array of arrays.
	 * @param string|array $type Value(s) of filter key to remove.
	 *
	 * @return array Filtered array.
	 */
	protected function filter_disabled( $args, $type ) {
		return $this->filter_on_key_value( $args, $type, 'disable' );
	}

	/**
	 * Filter on key value.
	 *
	 * @param array  $args      Multidimensional array of arrays.
	 * @param string $type      Value(s) of filter key to remove.
	 * @param string $filterkey The key to filter on.
	 *
	 * @return array Filtered array.
	 */
	protected function filter_on_key_value( $args, $type, $filterkey ) {
		foreach ( $args as $key => $value ) {
			if ( isset( $value[ $filterkey ] ) && in_array( $type, (array) $value[ $filterkey ] ) ) {
				unset( $args[ $key ] );
			}
		}

		return $args;
	}

	/**
	 * Only meta filters.
	 *
	 * @param array $args The arguments.
	 *
	 * @return array The filtered arguments.
	 */
	protected function only_meta_filters( $args ) {
		foreach ( $args as $k => $v ) {
			if ( ! isset( $v['meta'] ) ) {
				unset( $args[ $k ] );
			}
		}
		return $this->filter_disabled( $args, 'metabox' );
	}

	/**
	 * Check if the plugin is active.
	 *
	 * @return bool Whether the plugin is active.
	 */
	protected function is_active() {
		$desired_screen = 'edit-' . $this->post_type;

		// Exit early on autosave.
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return false;
		}

		// phpcs:disable WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended
		// Inline save?
		if ( defined( 'DOING_AJAX' ) && DOING_AJAX && isset( $_POST['screen'] ) && $desired_screen === $_POST['screen'] ) {
			return true;
		}

		$screen = get_current_screen();
		if ( ! $screen ) {
			global $pagenow;
			if ( 'edit.php' === $pagenow ) {
				if ( isset( $_GET['post_type'] ) && $this->post_type === $_GET['post_type'] ) {
					return true;
				}

				if ( 'post' === $this->post_type ) {
					return true;
				}

				return false;
			}
		}

		// phpcs:enable WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended

		if ( is_object( $screen ) && isset( $screen->id ) ) {
			return $desired_screen === $screen->id;
		}

		return false;
	}

	/**
	 * Log data.
	 *
	 * @param array $data The data to log.
	 *
	 * @return void
	 */
	public function log( $data ) {
		error_log( print_r( $data, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log, WordPress.PHP.DevelopmentFunctions.error_log_print_r
	}
}

require_once 'lib/template-tags.php';