* @package Achievements * @subpackage Loader */ /* Plugin Name: Achievements Plugin URI: http://achievementsapp.com/ Description: Achievements gamifies your WordPress site with challenges, badges, and points. Version: 3.2.1 Requires at least: 3.6 Tested up to: 3.6 License: GPLv3 Author: Paul Gibbs Author URI: http://byotos.com/ Domain Path: ../../languages/plugins/achievements/ Text Domain: dpa "Achievements" Copyright (C) 2009-13 Paul Gibbs This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. */ // Exit if accessed directly if ( ! defined( 'ABSPATH' ) ) exit; if ( ! class_exists( 'DPA_Achievements_Loader' ) ) : /** * Main Achievements class * * @since Achievements (3.0) */ final class DPA_Achievements_Loader { /** * Achievements uses many variables, several of which can be filtered to * customise the way it operates. Most of these variables are stored in a * private array that gets updated with the help of PHP magic methods. * * This is a precautionary measure to avoid potential errors produced by * unanticipated direct manipulation of Achievements' run-time data. * * @see Achievements::setup_globals() * @var array */ private $data; /** * Current user * * @var stdClass|WP_User Empty when not logged in; WP_User object when logged in. (By ref) */ public $current_user; /** * Other plugins append data here. Used to store information about the supported plugin * and a list of its actions that you want to support. * * The items contained within this object need to derive from the {@link DPA_Extension} class. * * @var stdClass */ public $extensions; /** * @var array Achievement views */ public $views = array(); /** * @var array Overloads get_option() */ public $options = array(); /** * @var array Overloads get_user_meta() */ public $user_options = array(); /** * @var Achievements The one true Achievements */ private static $instance; /** * Main Achievements instance * * Insures that only one instance of Achievements exists in memory at any one * time. Also prevents needing to define globals all over the place. * * @return DPA_Achievements_Loader The one true Achievements * @see achievements() * @since Achievements (3.0) * @staticvar Achievements $instance */ public static function instance() { if ( ! isset( self::$instance ) ) { self::$instance = new DPA_Achievements_Loader; self::$instance->setup_globals(); self::$instance->includes(); self::$instance->setup_actions(); } return self::$instance; } // Magic Methods /** * A dummy constructor to prevent Achievements from being loaded more than once. * * @since Achievements (3.0) */ private function __construct() {} /** * A dummy magic method to prevent Achievements from being cloned * * @since Achievements (3.0) */ public function __clone() { _doing_it_wrong( __FUNCTION__, __( 'Cheatin’ huh?', 'dpa' ), '3.0' ); } /** * A dummy magic method to prevent Achievements from being unserialised * * @since Achievements (3.0) */ public function __wakeup() { _doing_it_wrong( __FUNCTION__, __( 'Cheatin’ huh?', 'dpa' ), '3.0' ); } /** * Magic method for checking the existence of a certain custom field * * @param string $key * @since Achievements (3.0) */ public function __isset( $key ) { return isset( $this->data[$key] ); } /** * Magic method for getting Achievements variables * * @param string $key * @since Achievements (3.0) */ public function __get( $key ) { return isset( $this->data[$key] ) ? $this->data[$key] : null; } /** * Magic method for setting Achievements variables * * @param string $key * @param mixed $value * @since Achievements (3.0) */ public function __set( $key, $value ) { $this->data[$key] = $value; } /** * Magic method for unsetting Achievements variables * * @param string $key * @since Achievements (3.0) */ public function __unset( $key ) { if ( isset( $this->data[$key] ) ) unset( $this->data[$key] ); } // Private methods /** * Set up global variables * * @since Achievements (3.0) */ private function setup_globals() { // Versions $this->version = 3.0; $this->db_version = 300; // Paths - plugin $this->file = __FILE__; $this->basename = apply_filters( 'dpa_basenname', plugin_basename( $this->file ) ); $this->plugin_dir = apply_filters( 'dpa_plugin_dir_path', plugin_dir_path( $this->file ) ); $this->plugin_url = apply_filters( 'dpa_plugin_dir_url', plugin_dir_url ( $this->file ) ); // Paths - theme compatibility packs $this->themes_dir = apply_filters( 'dpa_themes_dir', trailingslashit( $this->plugin_dir . 'templates' ) ); $this->themes_url = apply_filters( 'dpa_themes_url', trailingslashit( $this->plugin_url . 'templates' ) ); // Paths - languages $this->lang_dir = apply_filters( 'dpa_lang_dir', trailingslashit( $this->plugin_dir . 'languages' ) ); // Includes $this->includes_dir = apply_filters( 'dpa_includes_dir', trailingslashit( $this->plugin_dir . 'includes' ) ); $this->includes_url = apply_filters( 'dpa_includes_url', trailingslashit( $this->plugin_url . 'includes' ) ); // Post type/endpoint/taxonomy identifiers $this->achievement_post_type = apply_filters( 'dpa_achievement_post_type', 'achievement' ); $this->achievement_progress_post_type = apply_filters( 'dpa_achievement_progress_post_type', 'dpa_progress' ); $this->authors_endpoint = apply_filters( 'dpa_authors_endpoint', 'achievements' ); $this->event_tax_id = apply_filters( 'dpa_event_tax_id', 'dpa_event' ); // Post status identifiers $this->locked_status_id = apply_filters( 'dpa_locked_post_status', 'dpa_locked' ); $this->unlocked_status_id = apply_filters( 'dpa_unlocked_post_status', 'dpa_unlocked' ); // Other identifiers $this->view_id = apply_filters( 'dpa_view_id', 'dpa_view' ); // Queries $this->current_achievement_id = 0; // Current achievement ID $this->achievement_query = new stdClass(); // Main achievement post type query $this->progress_query = new stdClass(); // Main dpa_progress post type query // Theme compat $this->theme_compat = new stdClass(); // Base theme compatibility class $this->filters = new stdClass(); // Used when adding/removing filters // Users $this->current_user = new stdClass(); // Currently logged in user -- @todo Is this redundant? // Other stuff $this->domain = 'dpa'; // Unique identifier for retrieving translated strings $this->errors = new WP_Error(); // Errors $this->extensions = new stdClass(); // Other plugins add data here // Deep integration with other plugins $this->integrate_into_buddypress = false; // Use BuddyPress profiles for screens like "my achievements" // Add to global cache groups wp_cache_add_global_groups( 'achievements' ); /** * If multisite and running network-wide, grab the options from the site options * table and store in achievements()->options. dpa_setup_option_filters() sets * up a pre_option filter which loads from achievements()->options if an option * has been set there. This saves a lot of conditionals throughout the plugin. */ if ( is_multisite() && dpa_is_running_networkwide() ) { $options = dpa_get_default_options(); foreach ( $options as $option_name => $option_value ) achievements()->options[$option_name] = get_site_option( $option_name ); } } /** * Include required files * * @since Achievements (3.0) */ private function includes() { /** * Classes */ require( $this->includes_dir . 'class-dpa-extension.php' ); // Base class for adding support for other plugins require( $this->includes_dir . 'class-dpa-cpt-extension.php' ); // Base class for adding support for other plugins using post type actions require( $this->includes_dir . 'class-dpa-shortcodes.php' ); /** * Core */ require( $this->includes_dir . 'core/dependency.php' ); require( $this->includes_dir . 'core/functions.php' ); require( $this->includes_dir . 'core/cache.php' ); require( $this->includes_dir . 'core/options.php' ); require( $this->includes_dir . 'core/caps.php' ); require( $this->includes_dir . 'core/update.php' ); /** * Templates */ require( $this->includes_dir . 'core/template-functions.php' ); require( $this->includes_dir . 'core/template-loader.php' ); require( $this->includes_dir . 'core/theme-compatibility.php' ); /** * Plugin extensions */ require( $this->includes_dir . 'extensions/bbpress.php' ); require( $this->includes_dir . 'extensions/buddypress.php' ); require( $this->includes_dir . 'extensions/buddystream.php' ); require( $this->includes_dir . 'extensions/inviteanyone.php' ); require( $this->includes_dir . 'extensions/scholarpress.php' ); require( $this->includes_dir . 'extensions/wordpress.php' ); require( $this->includes_dir . 'extensions/wpecommerce.php' ); require( $this->includes_dir . 'buddypress/functions.php' ); /** * Components */ require( $this->includes_dir . 'common/functions.php' ); require( $this->includes_dir . 'common/template.php' ); require( $this->includes_dir . 'common/widgets.php' ); require( $this->includes_dir . 'achievements/functions.php' ); require( $this->includes_dir . 'achievements/template.php' ); require( $this->includes_dir . 'progress/functions.php' ); require( $this->includes_dir . 'progress/template.php' ); require( $this->includes_dir . 'users/capabilities.php' ); require( $this->includes_dir . 'users/functions.php' ); require( $this->includes_dir . 'users/template.php' ); require( $this->includes_dir . 'users/options.php' ); require( $this->includes_dir . 'users/notifications.php' ); /** * Hooks */ require( $this->includes_dir . 'core/actions.php' ); require( $this->includes_dir . 'core/filters.php' ); /** * Admin */ if ( is_admin() ) { require( $this->includes_dir . 'admin/admin.php' ); require( $this->includes_dir . 'admin/actions.php' ); } } /** * Set up the default hooks and actions * * @since Achievements (3.0) */ private function setup_actions() { // Plugin activation and deactivation hooks add_action( 'activate_' . $this->basename, 'dpa_activation' ); add_action( 'deactivate_' . $this->basename, 'dpa_deactivation' ); // If Achievements is being deactivated, don't add any more actions if ( dpa_is_deactivation( $this->basename ) ) return; // Add the core actions $actions = array( 'setup_theme', // Setup the default theme compat 'setup_current_user', // Set up currently logged in user 'register_post_types', // Register post types (achievement, dpa_progress) 'register_post_statuses', // Register post statuses (dpa_progress: locked, unlocked) 'register_taxonomies', // Register taxonomies (dpa_event) 'register_shortcodes', // Register shortcodes 'register_theme_packages', // Register bundled theme packages (templates) 'load_textdomain', // Load textdomain 'constants', // Define constants 'register_endpoints', // Register endpoints (achievements) 'admin_bar_menu', // Register custom menu items (My Achievements) ); foreach( $actions as $class_action ) add_action( 'dpa_' . $class_action, array( $this, $class_action ), 5 ); // All Achievements actions are setup (includes core/actions.php) do_action_ref_array( 'dpa_after_setup_actions', array( &$this ) ); } /** * Define constants * * @since Achievements (3.0) */ public function constants() { // If multisite and running network-wide, we switch_to_blog to this site to store/fetch achievement data if ( ! defined( 'DPA_DATA_STORE' ) ) define( 'DPA_DATA_STORE', 1 ); } /** * Load the translation file for current language. Checks the default WordPress languages folder. * * @since Achievements (3.0) */ public function load_textdomain() { // Traditional WordPress plugin locale filter $locale = apply_filters( 'plugin_locale', get_locale(), $this->domain ); $mofile = sprintf( '%1$s-%2$s.mo', $this->domain, $locale ); // Look in global /wp-content/languages/plugins/ folder $mofile_global = WP_LANG_DIR . '/plugins/' . $mofile; if ( file_exists( $mofile_global ) ) load_textdomain( $this->domain, $mofile_global ); } /** * Register endpoints * * @since Achievements (3.0) */ public function register_endpoints() { // If we're integrating into BP user profiles, bail out. if ( dpa_integrate_into_buddypress() ) return; add_rewrite_endpoint( dpa_get_authors_endpoint(), EP_AUTHORS ); // /authors/paul/[achievements] } /** * Set up the post types for: achievement, achievement_progress * * @since Achievements (3.0) */ public function register_post_types() { $cpt = $labels = $rewrite = $supports = array(); // CPT labels $labels['achievement'] = array( 'add_new' => _x( 'Add New', 'achievement', 'dpa' ), 'add_new_item' => __( 'Add New Achievement', 'dpa' ), 'all_items' => __( 'All Achievements', 'dpa' ), 'edit' => _x( 'Edit', 'achievement', 'dpa' ), 'edit_item' => __( 'Edit Achievement', 'dpa' ), 'menu_name' => __( 'Achievements', 'dpa' ), 'name' => __( 'Achievements', 'dpa' ), 'new_item' => __( 'New Achievement', 'dpa' ), 'not_found' => __( 'No achievements found.', 'dpa' ), 'not_found_in_trash' => __( 'No achievements found in Trash.', 'dpa' ), 'search_items' => __( 'Search Achievements', 'dpa' ), 'singular_name' => __( 'Achievement', 'dpa' ), 'view' => __( 'View Achievement', 'dpa' ), 'view_item' => __( 'View Achievement', 'dpa' ), ); // CPT rewrite $rewrite['achievement'] = array( 'ep_mask' => 0, // EP_ROOT - removes comment-page rewrite rules 'feed' => false, // Remove feed rewrite rules 'feeds' => false, // Remove feed rewrite rules (this is what the parameter ought to be) 'pages' => true, 'slug' => dpa_get_root_slug(), 'with_front' => false, ); // CPT supports $supports['achievement'] = array( 'editor', 'revisions', 'thumbnail', 'title', ); $supports['achievement_progress'] = array( 'author', ); // CPT filter $cpt['achievement'] = apply_filters( 'dpa_register_post_type_achievement', array( 'can_export' => true, 'capabilities' => dpa_get_achievement_caps(), 'capability_type' => array( 'achievement', 'achievements' ), 'delete_with_user' => false, 'description' => _x( 'Achievements types (e.g. new post, new site, new user)', 'Achievement post type description', 'dpa' ), 'exclude_from_search' => false, 'has_archive' => true, 'hierarchical' => false, 'labels' => $labels['achievement'], 'public' => true, 'publicly_queryable' => true, 'query_var' => true, 'rewrite' => $rewrite['achievement'], 'register_meta_box_cb' => 'dpa_admin_setup_metaboxes', 'show_in_admin_bar' => true, 'show_in_menu' => true, 'show_in_nav_menus' => true, 'show_ui' => dpa_current_user_can_see( dpa_get_achievement_post_type() ), 'supports' => $supports['achievement'], ) ); $cpt['achievement_progress'] = apply_filters( 'dpa_register_post_type_achievement_progress', array( 'can_export' => true, 'capabilities' => dpa_get_achievement_progress_caps(), 'capability_type' => array( 'achievement_progress', 'achievement_progresses' ), 'delete_with_user' => true, 'description' => _x( 'Achievement Progress (e.g. unlocked achievements for a user, progress on an achievement for a user)', 'Achievement Progress post type description', 'dpa' ), 'exclude_from_search' => true, 'has_archive' => false, 'hierarchical' => false, 'public' => false, 'publicly_queryable' => false, 'query_var' => false, 'rewrite' => false, 'show_in_admin_bar' => false, 'show_in_menu' => false, 'show_in_nav_menus' => false, 'show_ui' => false, 'supports' => $supports['achievement_progress'], ) ); // Register Achievement post type register_post_type( dpa_get_achievement_post_type(), $cpt['achievement'] ); // Register Achievement Progress post type register_post_type( dpa_get_progress_post_type(), $cpt['achievement_progress'] ); } /** * Register the post statuses used by Achievements * * @since Achievements (3.0) */ public function register_post_statuses() { // Locked register_post_status( dpa_get_locked_status_id(), apply_filters( 'dpa_register_locked_post_status', array( 'label' => _x( 'Locked', 'achievement', 'dpa' ), 'label_count' => _nx_noop( 'Locked (%s)', 'Locked (%s)', 'dpa' ), 'public' => false, 'exclude_from_search' => true, 'show_in_admin_status_list' => true, 'show_in_admin_all_list' => true, ) ) ); // Unlocked register_post_status( dpa_get_unlocked_status_id(), apply_filters( 'dpa_register_unlocked_post_status', array( 'label' => _x( 'Unlocked', 'achievement', 'dpa' ), 'label_count' => _nx_noop( 'Unlocked (%s)', 'Unlocked (%s)', 'dpa' ), 'public' => false, 'exclude_from_search' => true, 'show_in_admin_status_list' => true, 'show_in_admin_all_list' => true, ) ) ); } /** * Register the achievement event taxonomy * * @since Achievements (3.0) */ public function register_taxonomies() { $labels = $tax = array(); // Event tax labels $labels['event'] = array( 'add_new_item' => __( 'Add New Event', 'dpa' ), 'all_items' => __( 'All', 'dpa' ), 'edit_item' => __( 'Edit Event', 'dpa' ), 'name' => _x( 'Events', 'event taxonomy general name', 'dpa' ), 'new_item_name' => __( 'New Event Name', 'dpa' ), 'popular_items' => __( 'Popular Events', 'dpa' ), 'search_items' => __( 'Search Events', 'dpa' ), 'singular_name' => _x( 'Event', 'event taxonomy singular name', 'dpa' ), 'update_item' => __( 'Update Event', 'dpa' ), 'view_item' => __( 'View Event', 'dpa' ), ); // Action filter $tax = apply_filters( 'dpa_register_taxonomies_action', array( 'capabilities' => dpa_get_event_caps(), 'hierarchical' => false, 'labels' => $labels['event'], 'public' => false, 'query_var' => false, 'rewrite' => false, 'show_in_nav_menus' => false, 'show_tagcloud' => false, 'show_ui' => dpa_is_developer_mode(), 'update_count_callback' => '_update_post_term_count', ) ); // Register the achievement event taxonomy register_taxonomy( dpa_get_event_tax_id(), // The event taxonomy id dpa_get_achievement_post_type(), // The achievement post type $tax ); } /** * Register bundled theme packages * * Note that since we currently have complete control over the /templates/ * folders, it's fine to hardcode these here. If at a later date we need to * automate this, an API will need to be built. * * @since Achievements (3.0) */ public function register_theme_packages() { dpa_register_theme_package( array( 'id' => 'default', 'name' => __( 'Achievements Default', 'dpa' ), 'version' => dpa_get_version(), 'dir' => trailingslashit( $this->themes_dir . 'achievements' ), 'url' => trailingslashit( $this->themes_url . 'achievements' ) ) ); } /** * Register Achievements' shortcodes * * @since Achievements (3.0) */ public function register_shortcodes() { $this->shortcodes = new DPA_Shortcodes(); } /** * Register custom menu items * * @global WP_Admin_Bar $wp_admin_bar * @since Achievements (3.0) */ public function admin_bar_menu() { global $wp_admin_bar; if ( ! dpa_is_user_active() ) return; $wp_admin_bar->add_node( array( 'href' => dpa_get_user_avatar_link( 'type=url' ), 'id' => 'dpa_my_achievements', 'parent' => 'user-actions', 'title' => _x( 'My Achievements', 'Menu item in the toolbar', 'dpa' ), ) ); } /** * Set up the currently logged in user. * * Do not call this before the 'init' action has started. * * @since Achievements (3.0) */ public function setup_current_user() { $this->current_user = &wp_get_current_user(); } /** * Setup the default Achievements theme compatibility location. * * @since Achievements (3.0) */ public function setup_theme() { // Bail if something already has this under control if ( ! empty( $this->theme_compat->theme ) ) return; // Setup the theme package to use for compatibility dpa_setup_theme_compat( dpa_get_theme_package_id() ); } } /** * Checks if the plugin across entire network, rather than on a specific site (for multisite) * * Needs to be in scope for DPA_Achievements_Loader::setup_globals(), so it's not in core/options.php * * @return bool * @since Achievements (3.0) * @todo Review if is_plugin_active_for_network() not being available on Network Activation is a WP core bug. */ function dpa_is_running_networkwide() { $retval = false; if ( is_multisite() ) { $plugins = get_site_option( 'active_sitewide_plugins' ); if ( isset( $plugins[achievements()->basename] ) ) $retval = true; } return (bool) apply_filters( 'dpa_is_running_networkwide', $retval ); } /** * Get the default site options and their values * * Needs to be in scope for DPA_Achievements_Loader::setup_globals(), so it's not in core/options.php * * @return array Option names and values * @since Achievements (3.0) */ function dpa_get_default_options() { $options = array( // DB version '_dpa_db_version' => achievements()->db_version, // Initial DB version // Settings '_dpa_theme_package_id' => 'default', // The ID for the current theme package. // Achievement post type '_dpa_achievements_per_page' => 15, // Achievements per page '_dpa_achievements_per_rss_page' => 25, // Achievements per RSS page '_dpa_root_slug' => 'achievements', // Achievements archive slug // Progress post type '_dpa_progresses_per_page' => 15, // Progresses per page '_dpa_progresses_per_rss_page' => 25, // Progresses per RSS page // Extension support '_dpa_extension_versions' => array(), // Version numbers for the plugin extensions // Stats '_dpa_stats_last_achievement_id' => 0, // ID of the last unlocked achievement '_dpa_stats_last_achievement_user_id' => 0, // ID of the user who unlocked the last achievement ); return apply_filters( 'dpa_get_default_options', $options ); } /** * The main function responsible for returning the one true Achievements instance. * * Use this function like you would a global variable, except without needing * to declare the global. * * @return DPA_Achievements_Loader The one true Achievements instance * @since Achievements (3.0) */ function achievements() { return DPA_Achievements_Loader::instance(); } /** * Hook Achievements early onto the 'plugins_loaded' action. * * This gives all other plugins the chance to load before Achievements to get their * actions, filters, and overrides setup without Achievements being in the way. */ if ( defined( 'DPA_LATE_LOAD' ) ) { add_action( 'plugins_loaded', 'achievements', (int) DPA_LATE_LOAD ); // This makes it go up to 11 } else { achievements(); } endif; // class_exists check