load_dependencies(); $this->define_admin_hooks(); $this->define_public_hooks(); $this->define_statistics_hooks(); $this->blocks_init(); $this->widgets_init(); $this->set_meta_caps(); } /** * Load the required dependencies for this plugin. * * Create an instance of the loader which will be used to register the hooks * with WordPress. * * @since 1.0.0 * @access private */ private function load_dependencies() { /** * The class responsible for orchestrating the actions and filters of the * core plugin. */ require_once AIOPOD_PLUGIN_DIR . 'includes/loader.php'; /** * The class responsibe for defining custom capabilities. */ require_once AIOPOD_PLUGIN_DIR . 'includes/roles.php'; /** * The custom walker classes for the 'wp_dropdown_categories' function. */ require_once AIOPOD_PLUGIN_DIR . 'includes/walker-terms-dropdown.php'; require_once AIOPOD_PLUGIN_DIR . 'includes/walker-terms-multiselect.php'; /** * The files with the helper functions. */ require_once AIOPOD_PLUGIN_DIR . 'includes/helpers/functions.php'; require_once AIOPOD_PLUGIN_DIR . 'includes/helpers/render.php'; require_once AIOPOD_PLUGIN_DIR . 'includes/helpers/urls.php'; require_once AIOPOD_PLUGIN_DIR . 'includes/helpers/transcripts.php'; /** * The class responsible for statistics tracking and the download tracking URL handler. */ require_once AIOPOD_PLUGIN_DIR . 'includes/statistics.php'; /** * The classes responsible for defining all actions that occur in the admin area. */ require_once AIOPOD_PLUGIN_DIR . 'admin/admin.php'; require_once AIOPOD_PLUGIN_DIR . 'admin/podcasts.php'; require_once AIOPOD_PLUGIN_DIR . 'admin/episodes.php'; require_once AIOPOD_PLUGIN_DIR . 'admin/categories.php'; require_once AIOPOD_PLUGIN_DIR . 'admin/tags.php'; require_once AIOPOD_PLUGIN_DIR . 'admin/participants.php'; require_once AIOPOD_PLUGIN_DIR . 'admin/settings.php'; require_once AIOPOD_PLUGIN_DIR . 'admin/shortcode-builder.php'; require_once AIOPOD_PLUGIN_DIR . 'admin/help-tutorials.php'; require_once AIOPOD_PLUGIN_DIR . 'admin/import.php'; /** * The classes responsible for defining all actions that occur in the public-facing * side of the site. */ require_once AIOPOD_PLUGIN_DIR . 'public/public.php'; require_once AIOPOD_PLUGIN_DIR . 'public/yoast.php'; require_once AIOPOD_PLUGIN_DIR . 'public/rank-math.php'; require_once AIOPOD_PLUGIN_DIR . 'public/pmpro-cpt.php'; require_once AIOPOD_PLUGIN_DIR . 'public/pmpro-member-rss.php'; require_once AIOPOD_PLUGIN_DIR . 'public/podcasts.php'; require_once AIOPOD_PLUGIN_DIR . 'public/podcast.php'; require_once AIOPOD_PLUGIN_DIR . 'public/episodes.php'; require_once AIOPOD_PLUGIN_DIR . 'public/episode.php'; require_once AIOPOD_PLUGIN_DIR . 'public/categories.php'; require_once AIOPOD_PLUGIN_DIR . 'public/tags.php'; require_once AIOPOD_PLUGIN_DIR . 'public/participants.php'; require_once AIOPOD_PLUGIN_DIR . 'public/feed.php'; require_once AIOPOD_PLUGIN_DIR . 'public/transcript.php'; require_once AIOPOD_PLUGIN_DIR . 'public/multilingual.php'; /** * The class responsible for defining actions that occur in the gutenberg blocks. */ require_once AIOPOD_PLUGIN_DIR. 'blocks/blocks.php'; /** * The classes responsible for defining all actions that occur in the widgets. */ require_once AIOPOD_PLUGIN_DIR . 'widgets/podcasts.php'; require_once AIOPOD_PLUGIN_DIR . 'widgets/episodes.php'; require_once AIOPOD_PLUGIN_DIR . 'widgets/categories.php'; require_once AIOPOD_PLUGIN_DIR . 'widgets/tags.php'; require_once AIOPOD_PLUGIN_DIR . 'widgets/participants.php'; $this->loader = new AIOPOD_Loader(); } /** * Register all of the hooks related to the admin area functionality * of the plugin. * * @since 1.0.0 * @access private */ private function define_admin_hooks() { // Hooks common to all admin pages $admin = new AIOPOD_Admin(); $this->loader->add_action( 'admin_init', $admin, 'insert_missing_options', 2 ); $this->loader->add_action( 'admin_menu', $admin, 'admin_menu' ); $this->loader->add_action( 'admin_enqueue_scripts', $admin, 'enqueue_styles' ); $this->loader->add_action( 'admin_enqueue_scripts', $admin, 'enqueue_scripts' ); $this->loader->add_action( 'elementor/editor/after_enqueue_styles', $admin, 'enqueue_styles' ); $this->loader->add_action( 'elementor/editor/after_enqueue_scripts', $admin, 'enqueue_scripts' ); $this->loader->add_action( 'update_option_aiopod_taxonomies_settings', $admin, 'update_core_term_counts', 10, 2 ); $this->loader->add_action( 'update_option_aiopod_pages_settings', $admin, 'force_rewrite_rules_on_settings_update' ); $this->loader->add_action( 'save_post_page', $admin, 'force_rewrite_rules_on_page_update', 10, 3 ); $this->loader->add_filter( 'display_post_states', $admin, 'add_display_post_states', 10, 2 ); $this->loader->add_filter( 'plugin_action_links_' . AIOPOD_PLUGIN_FILE_NAME, $admin, 'plugin_action_links' ); // Hooks specific to the podcasts page $podcasts = new AIOPOD_Admin_Podcasts(); $this->loader->add_action( 'admin_menu', $podcasts, 'admin_menu' ); $this->loader->add_action( 'init', $podcasts, 'register_post_type' ); $this->loader->add_action( 'before_delete_post', $podcasts, 'before_delete_post' ); if ( is_admin() ) { $this->loader->add_action( 'post_submitbox_misc_actions', $podcasts, 'post_submitbox_misc_actions' ); $this->loader->add_action( 'add_meta_boxes', $podcasts, 'add_meta_boxes' ); $this->loader->add_action( 'save_post', $podcasts, 'save_meta_data', 10, 2 ); $this->loader->add_action( 'restrict_manage_posts', $podcasts, 'restrict_manage_posts' ); $this->loader->add_action( 'manage_aiopod_podcasts_posts_custom_column', $podcasts, 'custom_column_content', 10, 2 ); $this->loader->add_filter( 'parent_file', $podcasts, 'parent_file' ); $this->loader->add_filter( 'admin_url', $podcasts, 'filter_admin_url', 10, 2 ); $this->loader->add_filter( 'enter_title_here', $podcasts, 'change_default_title' ); $this->loader->add_filter( 'parse_query', $podcasts, 'parse_query' ); $this->loader->add_filter( 'post_row_actions', $podcasts, 'row_actions', 10, 2 ); $this->loader->add_filter( 'manage_edit-aiopod_podcasts_columns', $podcasts, 'get_columns' ); $this->loader->add_filter( 'manage_edit-aiopod_podcasts_sortable_columns', $podcasts, 'sortable_columns' ); $this->loader->add_filter( 'use_block_editor_for_post_type', $podcasts, 'disable_gutenberg', 10, 2 ); $this->loader->add_filter( 'gutenberg_can_edit_post_type', $podcasts, 'disable_gutenberg', 10, 2 ); } // Hooks specific to the episodes page $episodes = new AIOPOD_Admin_Episodes(); $this->loader->add_action( 'admin_menu', $episodes, 'admin_menu' ); $this->loader->add_action( 'init', $episodes, 'register_post_type' ); $this->loader->add_action( 'trashed_post', $episodes, 'trashed_post' ); $this->loader->add_action( 'before_delete_post', $episodes, 'before_delete_post' ); if ( is_admin() ) { $this->loader->add_action( 'post_submitbox_misc_actions', $episodes, 'post_submitbox_misc_actions' ); $this->loader->add_action( 'add_meta_boxes', $episodes, 'add_meta_boxes' ); $this->loader->add_action( 'save_post', $episodes, 'save_meta_data', 10, 2 ); $this->loader->add_action( 'restrict_manage_posts', $episodes, 'restrict_manage_posts' ); $this->loader->add_action( 'manage_aiopod_episodes_posts_custom_column', $episodes, 'custom_column_content', 10, 2 ); $this->loader->add_filter( 'parent_file', $episodes, 'parent_file' ); $this->loader->add_filter( 'enter_title_here', $episodes, 'change_default_title' ); $this->loader->add_filter( 'parse_query', $episodes, 'parse_query' ); $this->loader->add_filter( 'post_row_actions', $episodes, 'row_actions', 10, 2 ); $this->loader->add_filter( 'manage_edit-aiopod_episodes_columns', $episodes, 'get_columns' ); $this->loader->add_filter( 'manage_edit-aiopod_episodes_sortable_columns', $episodes, 'sortable_columns' ); $this->loader->add_filter( 'use_block_editor_for_post_type', $episodes, 'disable_gutenberg', 10, 2 ); $this->loader->add_filter( 'gutenberg_can_edit_post_type', $episodes, 'disable_gutenberg', 10, 2 ); } // Hooks specific to the categories page $categories = new AIOPOD_Admin_Categories(); $this->loader->add_action( 'admin_menu', $categories, 'admin_menu' ); $this->loader->add_action( 'init', $categories, 'register_taxonomy' ); $this->loader->add_action( 'admin_post_aiopod_import_categories', $categories, 'import_categories' ); $this->loader->add_action( 'admin_notices', $categories, 'admin_notices' ); $this->loader->add_action( 'aiopod_categories_add_form_fields', $categories, 'add_form_fields' ); $this->loader->add_action( 'aiopod_categories_edit_form_fields', $categories, 'edit_form_fields' ); $this->loader->add_action( 'created_aiopod_categories', $categories, 'save_form_fields' ); $this->loader->add_action( 'edited_aiopod_categories', $categories, 'save_form_fields' ); $this->loader->add_action( 'pre_delete_term', $categories, 'pre_delete_term', 10, 2 ); $this->loader->add_filter( 'parent_file', $categories, 'parent_file' ); $this->loader->add_filter( "manage_edit-aiopod_categories_columns", $categories, 'get_columns' ); $this->loader->add_filter( "manage_edit-aiopod_categories_sortable_columns", $categories, 'get_columns' ); $this->loader->add_filter( "manage_aiopod_categories_custom_column", $categories, 'custom_column_content', 10, 3 ); // Hooks specific to the tags page $tags = new AIOPOD_Admin_Tags(); $this->loader->add_action( 'admin_menu', $tags, 'admin_menu' ); $this->loader->add_action( 'init', $tags, 'register_taxonomy' ); $this->loader->add_filter( 'parent_file', $tags, 'parent_file' ); $this->loader->add_filter( "manage_edit-aiopod_tags_columns", $tags, 'get_columns' ); $this->loader->add_filter( "manage_edit-aiopod_tags_sortable_columns", $tags, 'get_columns' ); $this->loader->add_filter( "manage_aiopod_tags_custom_column", $tags, 'custom_column_content', 10, 3 ); // Hooks specific to the participants page $participants = new AIOPOD_Admin_Participants(); $this->loader->add_action( 'admin_init', $participants, 'admin_init' ); $this->loader->add_action( 'admin_menu', $participants, 'admin_menu' ); $this->loader->add_action( 'init', $participants, 'register_taxonomy' ); $this->loader->add_action( 'aiopod_participants_add_form_fields', $participants, 'add_form_fields' ); $this->loader->add_action( 'aiopod_participants_edit_form_fields', $participants, 'edit_form_fields' ); $this->loader->add_action( 'created_aiopod_participants', $participants, 'save_form_fields' ); $this->loader->add_action( 'edited_aiopod_participants', $participants, 'save_form_fields' ); $this->loader->add_action( 'pre_delete_term', $participants, 'pre_delete_term', 10, 2 ); $this->loader->add_filter( 'parent_file', $participants, 'parent_file' ); $this->loader->add_filter( "manage_edit-aiopod_participants_columns", $participants, 'get_columns' ); $this->loader->add_filter( "manage_edit-aiopod_participants_sortable_columns", $participants, 'get_columns' ); $this->loader->add_filter( "manage_aiopod_participants_custom_column", $participants, 'custom_column_content', 10, 3 ); // Hooks specific to the settings page $settings = new AIOPOD_Admin_Settings(); $this->loader->add_action( 'admin_menu', $settings, 'admin_menu' ); $this->loader->add_action( 'admin_init', $settings, 'admin_init' ); // Hooks specific to the shortcode builder page $shortcode_builder = new AIOPOD_Admin_Shortcode_Builder(); $this->loader->add_action( 'admin_menu', $shortcode_builder, 'admin_menu' ); // Hooks specific to the help & tutorials page $help_tutorials = new AIOPOD_Admin_Help_Tutorials(); $this->loader->add_action( 'admin_menu', $help_tutorials, 'admin_menu', 99 ); // Hooks specific to the podcast import form $import = new AIOPOD_Admin_Import(); $this->loader->add_action( 'init', $import, 'schedule_events' ); $this->loader->add_action( 'aiopod_schedule_every_five_minutes', $import, 'cron_event' ); $this->loader->add_action( 'wp_ajax_aiopod_import_podcast', $import, 'ajax_callback_import_podcast' ); $this->loader->add_filter( 'cron_schedules', $import, 'cron_schedules' ); } /** * Register all of the hooks related to the public-facing functionality * of the plugin. * * @since 1.0.0 * @access private */ private function define_public_hooks() { // Hooks common to all public pages $public = new AIOPOD_Public(); $this->loader->add_action( 'template_redirect', $public, 'template_redirect', 0 ); $this->loader->add_action( 'init', $public, 'init', 11 ); $this->loader->add_action( 'wp_enqueue_scripts', $public, 'register_styles', 99 ); $this->loader->add_action( 'wp_enqueue_scripts', $public, 'register_scripts', 99 ); $this->loader->add_action( 'enqueue_block_assets', $public, 'enqueue_block_assets' ); $this->loader->add_action( 'elementor/editor/after_enqueue_scripts', $public, 'enqueue_editor_assets' ); $this->loader->add_action( 'elementor/preview/enqueue_scripts', $public, 'enqueue_editor_assets' ); $this->loader->add_action( 'wp', $public, 'set_mysql_rand_seed_value' ); $this->loader->add_action( 'wp_loaded', $public, 'maybe_flush_rules', 11 ); $this->loader->add_action( 'wp_head', $public, 'wp_head' ); $this->loader->add_action( 'pre_get_posts', $public, 'include_in_core_archives', 99 ); if ( ! aiopod_is_yoast_or_rank_math_active() ) { $this->loader->add_filter( 'wp_title', $public, 'wp_title', 99, 3 ); $this->loader->add_filter( 'document_title_parts', $public, 'document_title_parts' ); } $this->loader->add_filter( 'query_vars', $public, 'query_vars' ); $this->loader->add_filter( 'request', $public, 'resolve_archive_child_pages' ); $this->loader->add_filter( 'the_title', $public, 'the_title', 99, 2 ); $this->loader->add_filter( 'single_post_title', $public, 'the_title', 99 ); $this->loader->add_filter( 'has_post_thumbnail', $public, 'has_post_thumbnail', 10, 3 ); $this->loader->add_filter( 'post_thumbnail_html', $public, 'post_thumbnail_html', 10, 5 ); $this->loader->add_filter( 'term_link', $public, 'term_link', 10, 3 ); // Hooks specific to the Yoast SEO plugin $yoast = new AIOPOD_Public_Yoast(); $this->loader->add_filter( 'wpseo_title', $yoast, 'wpseo_title' ); $this->loader->add_filter( 'wpseo_opengraph_title', $yoast, 'wpseo_title' ); $this->loader->add_filter( 'wpseo_metadesc', $yoast, 'wpseo_metadesc' ); $this->loader->add_filter( 'wpseo_opengraph_desc', $yoast, 'wpseo_metadesc' ); $this->loader->add_filter( 'wpseo_canonical', $yoast, 'wpseo_canonical' ); $this->loader->add_filter( 'wpseo_opengraph_url', $yoast, 'wpseo_canonical' ); $this->loader->add_filter( 'wpseo_opengraph_image', $yoast, 'wpseo_opengraph_image' ); $this->loader->add_filter( 'wpseo_twitter_image', $yoast, 'wpseo_twitter_image' ); $this->loader->add_filter( 'wpseo_breadcrumb_links', $yoast, 'wpseo_breadcrumb_links' ); // Hooks specific to the Rank Math SEO plugin $rank_math = new AIOPOD_Public_Rank_Math(); $this->loader->add_filter( 'rank_math/frontend/title', $rank_math, 'meta_title' ); $this->loader->add_filter( 'rank_math/frontend/description', $rank_math, 'meta_description' ); $this->loader->add_filter( 'rank_math/frontend/canonical', $rank_math, 'canonical_url' ); $this->loader->add_filter( 'rank_math/opengraph/facebook/image', $rank_math, 'opengraph_image_url' ); $this->loader->add_filter( 'rank_math/opengraph/twitter/image', $rank_math, 'opengraph_image_url' ); $this->loader->add_filter( 'rank_math/frontend/breadcrumb/items', $rank_math, 'breadcrumb_items' ); // Hooks specific to the Paid Memberships Pro plugin $pmpro_cpt = new AIOPOD_Public_PMPro_CPT(); $this->loader->add_filter( 'aiopod_can_owner_access', $pmpro_cpt, 'filter_owner_access', 10, 2 ); $this->loader->add_filter( 'aiopod_current_user_can', $pmpro_cpt, 'filter_user_access', 10, 3 ); $this->loader->add_filter( 'aiopod_is_content_restricted', $pmpro_cpt, 'filter_is_content_restricted', 10, 2 ); $this->loader->add_filter( 'aiopod_access_denied_html', $pmpro_cpt, 'filter_access_denied_html', 10, 4 ); $this->loader->add_filter( 'pmpro_search_filter_post_types', $pmpro_cpt, 'filter_search_filter_post_types' ); // Hooks specific to the Member RSS add-on for Paid Memberships Pro $pmpro_member_rss = new AIOPOD_Public_PMPro_Member_RSS(); $this->loader->add_action( 'template_redirect', $pmpro_member_rss, 'authenticate_request', -1 ); $this->loader->add_action( 'template_redirect', $pmpro_member_rss, 'restore_user_after_handlers', 1 ); $this->loader->add_action( 'save_post', $pmpro_member_rss, 'bump_feed_cache_version', 10, 2 ); $this->loader->add_action( 'before_delete_post', $pmpro_member_rss, 'forget_feed_cache_version', 10, 2 ); $this->loader->add_filter( 'aiopod_feed_includes_content', $pmpro_member_rss, 'filter_feed_includes_content', 10, 3 ); $this->loader->add_filter( 'aiopod_episode_file_url', $pmpro_member_rss, 'filter_episode_file_url', 10, 2 ); $this->loader->add_filter( 'aiopod_transcript_url', $pmpro_member_rss, 'filter_transcript_url', 10, 4 ); $this->loader->add_filter( 'aiopod_feed_cache_key', $pmpro_member_rss, 'filter_feed_cache_key', 10, 2 ); $this->loader->add_filter( 'pmpromrss_feeds', $pmpro_member_rss, 'filter_member_feeds' ); // Hooks specific to the podcasts page $podcasts = AIOPOD_Public_Podcasts::get_instance(); $this->loader->add_action( 'wp_ajax_aiopod_load_podcasts', $podcasts, 'ajax_callback_load_podcasts' ); $this->loader->add_action( 'wp_ajax_nopriv_aiopod_load_podcasts', $podcasts, 'ajax_callback_load_podcasts' ); // Hooks specific to the single podcast page $podcast = new AIOPOD_Public_Podcast(); $this->loader->add_filter( 'the_content', $podcast, 'the_content', 11 ); // Hooks specific to the episodes page $episodes = AIOPOD_Public_Episodes::get_instance(); $this->loader->add_action( 'wp_ajax_aiopod_load_episodes', $episodes, 'ajax_callback_load_episodes' ); $this->loader->add_action( 'wp_ajax_nopriv_aiopod_load_episodes', $episodes, 'ajax_callback_load_episodes' ); // Hooks specific to the single episode page $episode = new AIOPOD_Public_Episode(); $this->loader->add_filter( 'the_content', $episode, 'the_content', 11 ); $this->loader->add_filter( 'comments_open', $episode, 'comments_open', 10, 2 ); // Hooks specific to the categories page $categories = AIOPOD_Public_Categories::get_instance(); $this->loader->add_action( 'wp_ajax_aiopod_load_categories', $categories, 'ajax_callback_load_categories' ); $this->loader->add_action( 'wp_ajax_nopriv_aiopod_load_categories', $categories, 'ajax_callback_load_categories' ); // Hooks specific to the tags page $tags = AIOPOD_Public_Tags::get_instance(); // Hooks specific to the participants page $participants = AIOPOD_Public_Participants::get_instance(); $this->loader->add_action( 'wp_ajax_aiopod_load_participants', $participants, 'ajax_callback_load_participants' ); $this->loader->add_action( 'wp_ajax_nopriv_aiopod_load_participants', $participants, 'ajax_callback_load_participants' ); // Hooks that make the plugin multilingual compatible if ( ! is_admin() ) { $public_multilingual = new AIOPOD_Public_Multilingual(); $this->loader->add_action( 'init', $public, 'init', 11 ); $this->loader->add_filter( 'option_aiopod_pages_settings', $public_multilingual, 'filter_pages_settings_for_polylang' ); } // Hooks specific to the RSS feed output $feed = new AIOPOD_Public_Feed(); $this->loader->add_action( 'template_redirect', $feed, 'template_redirect', 0 ); $this->loader->add_action( 'save_post', $feed, 'bust_feed_cache', 10, 2 ); $this->loader->add_action( 'before_delete_post', $feed, 'bust_feed_cache', 10, 2 ); $this->loader->add_action( 'update_option_aiopod_restrictions_settings', $feed, 'flush_feed_caches' ); // Hooks specific to the transcript address $transcript = new AIOPOD_Public_Transcript(); $this->loader->add_action( 'template_redirect', $transcript, 'handle_request', 0 ); } /** * Register all hooks for the statistics tracking layer. * * AIOPOD_Statistics_Helper lives in includes/ and handles concerns that span both * the public (download interception, play tracking) and server (cron, * post-deletion cleanup) layers, so its hooks are registered separately * from define_admin_hooks() and define_public_hooks(). * * @since 1.0.0 * @access private */ private function define_statistics_hooks() { $statistics = AIOPOD_Statistics_Helper::get_instance(); $this->loader->add_action( 'template_redirect', $statistics, 'handle_download_request', 0 ); $this->loader->add_action( 'wp_ajax_aiopod_track_play', $statistics, 'ajax_callback_track_play' ); $this->loader->add_action( 'wp_ajax_nopriv_aiopod_track_play', $statistics, 'ajax_callback_track_play' ); $this->loader->add_action( 'before_delete_post', $statistics, 'delete_episode_stats' ); $this->loader->add_action( 'before_delete_post', $statistics, 'delete_podcast_stats' ); $this->loader->add_action( 'wp', $statistics, 'maybe_schedule_cleanup' ); $this->loader->add_action( 'aiopod_cleanup_statistics_logs', $statistics, 'run_cleanup_cron' ); } /** * Initialize Blocks. * * @since 1.0.0 * @access private */ private function blocks_init() { if ( is_admin() ) { global $pagenow; if ( 'widgets.php' === $pagenow ) return; } global $wp_version; $blocks = new AIOPOD_Blocks(); $this->loader->add_action( 'init', $blocks, 'register_block_types' ); $this->loader->add_action( 'enqueue_block_editor_assets', $blocks, 'enqueue_block_editor_assets' ); if ( version_compare( $wp_version, '5.8', '>=' ) ) { $this->loader->add_filter( 'block_categories_all', $blocks, 'block_categories' ); } else { $this->loader->add_filter( 'block_categories', $blocks, 'block_categories' ); } } /** * Add hook to register widgets. * * @since 1.0.0 * @access private */ private function widgets_init() { $this->loader->add_action( 'widgets_init', $this, 'register_widgets' ); } /** * Register widgets. * * @since 1.0.0 */ public function register_widgets() { register_widget( 'AIOPOD_Widget_Podcasts' ); register_widget( 'AIOPOD_Widget_Episodes' ); register_widget( 'AIOPOD_Widget_Categories' ); register_widget( 'AIOPOD_Widget_Tags' ); register_widget( 'AIOPOD_Widget_Participants' ); } /** * Map meta caps to primitive caps. * * @since 1.0.0 * @access private */ private function set_meta_caps() { $roles = new AIOPOD_Roles(); $this->loader->add_filter( 'map_meta_cap', $roles, 'meta_caps', 10, 4 ); } /** * Run the loader to execute all of the hooks with WordPress. * * @since 1.0.0 */ public function run() { $this->loader->run(); } }