This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ define( 'AD_CODE_MANAGER_VERSION', '0.2.2' ); define( 'AD_CODE_MANAGER_ROOT' , dirname( __FILE__ ) ); define( 'AD_CODE_MANAGER_FILE_PATH' , AD_CODE_MANAGER_ROOT . '/' . basename( __FILE__ ) ); define( 'AD_CODE_MANAGER_URL' , plugins_url( '/', __FILE__ ) ); // Bootsrap require_once( AD_CODE_MANAGER_ROOT .'/common/lib/acm-provider.php' ); require_once( AD_CODE_MANAGER_ROOT .'/common/lib/acm-wp-list-table.php' ); require_once( AD_CODE_MANAGER_ROOT .'/common/lib/acm-widget.php' ); require_once( AD_CODE_MANAGER_ROOT .'/common/lib/markdown.php' ); class Ad_Code_Manager { public $ad_codes = array(); public $whitelisted_conditionals = array(); public $title = 'Ad Code Manager'; public $post_type = 'acm-code'; public $plugin_slug = 'ad-code-manager'; public $manage_ads_cap = 'manage_options'; public $post_type_labels; public $logical_operator; public $ad_tag_ids; public $providers; public $current_provider_slug; public $current_provider; public $wp_list_table; /** * Instantiate the plugin * * @since 0.1 */ function __construct() { add_action( 'init', array( $this, 'action_load_providers' ) ); add_action( 'init', array( $this, 'action_init' ) ); // Incorporate the link to our admin menu add_action( 'admin_menu' , array( $this, 'action_admin_menu' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'register_scripts_and_styles' ) ); add_action( 'admin_print_scripts', array( $this, 'post_admin_header' ) ); add_action( 'wp_ajax_acm_admin_action', array( $this, 'handle_admin_action' ) ); add_action('current_screen', array( $this, 'contextual_help' ) ); add_action( 'widgets_init', array( $this, 'register_widget' ) ); add_shortcode( 'acm-tag' , array( $this, 'shortcode' ) ); // Workaround for PHP 5.4 warning: Creating default object from empty value in $this->providers = new stdClass(); } /** * Load all available ad providers * and set selected as ACM_Provider $current_provider * which holds all necessary configuration properties */ function action_load_providers() { $module_dirs = array_diff( scandir( AD_CODE_MANAGER_ROOT . '/providers/' ), array( '..', '.' ) ); foreach( $module_dirs as $module_dir ) { $module_dir = str_replace( '.php', '', $module_dir ); if ( file_exists( AD_CODE_MANAGER_ROOT . "/providers/$module_dir.php" ) ) { include_once( AD_CODE_MANAGER_ROOT . "/providers/$module_dir.php" ); } $tmp = explode( '-', $module_dir ); $class_name = ''; $slug_name = ''; $table_class_name = ''; foreach( $tmp as $word ) { $class_name .= ucfirst( $word ) . '_'; $slug_name .= $word . '_'; } $table_class_name = $class_name . 'ACM_WP_List_Table'; $class_name .= 'ACM_Provider'; $slug_name = rtrim( $slug_name, '_' ); // Store class names, but don't instantiate // We don't need them all at once if ( class_exists( $class_name ) ) { $this->providers->$slug_name = array( 'provider' => $class_name, 'table' => $table_class_name, ); } } /** * Configuration filter: acm_register_provider_slug * * We've already gathered a list of default providers by scanning the ACM plugin * directory for classes that we can use. To add a provider already included via * a different directory, the following filter is provided. */ $this->providers = apply_filters( 'acm_register_provider_slug', $this->providers ); /** * Configuration filter: acm_provider_slug * * By default we use doubleclick-for-publishers provider * To switch to a different ad provider use this filter */ $this->current_provider_slug = apply_filters( 'acm_provider_slug', 'doubleclick_for_publishers' ); // Instantiate one that we need if ( isset( $this->providers->{$this->current_provider_slug} ) ) $this->current_provider = new $this->providers->{$this->current_provider_slug}['provider']; // Nothing to do without a provider if ( !is_object( $this->current_provider ) ) return ; /** * Configuration filter: acm_whitelisted_script_urls * A security filter to whitelist which ad code script URLs can be added in the admin */ $this->current_provider->whitelisted_script_urls = apply_filters( 'acm_whitelisted_script_urls', $this->current_provider->whitelisted_script_urls ); } /** * Code to run on WordPress' 'init' hook * * @since 0.1 */ function action_init() { $this->post_type_labels = array( 'name' => __( 'DFP Ad Codes' ), 'singular_name' => __( 'DFP Ad Codes' ), ); // Allow other conditionals to be used $this->whitelisted_conditionals = array( 'is_home', 'is_front_page', 'is_category', 'has_category', 'is_page', 'is_tag', 'has_tag', ); /** * Configuration filter: acm_whitelisted_conditionals * Extend the list of usable conditional functions with your own awesome ones. */ $this->whitelisted_conditionals = apply_filters( 'acm_whitelisted_conditionals', $this->whitelisted_conditionals ); // Allow users to filter default logical operator $this->logical_operator = apply_filters( 'acm_logical_operator', 'OR' ); // Allow the ad management cap to be filtered if need be $this->manage_ads_cap = apply_filters( 'acm_manage_ads_cap', $this->manage_ads_cap ); // Load default ad tags for provider $this->ad_tag_ids = $this->current_provider->ad_tag_ids; /** * Configuration filter: acm_ad_tag_ids * Extend set of default tag ids. Ad tag ids are used as a parameter * for your template tag (e.g. do_action( 'acm_tag', 'my_top_leaderboard' )) */ $this->ad_tag_ids = apply_filters( 'acm_ad_tag_ids', $this->ad_tag_ids ); $this->register_acm_post_type(); // Ad tags are only run on the frontend if ( !is_admin() ) { add_action( 'acm_tag', array( $this, 'action_acm_tag' ) ); add_filter( 'acm_output_tokens', array( $this, 'filter_output_tokens' ), 5, 3 ); } // Load all of our registered ad codes $this->register_ad_codes( $this->get_ad_codes() ); } /** * Register our custom post type to store ad codes * * @since 0.1 */ function register_acm_post_type() { register_post_type( $this->post_type, array( 'labels' => $this->post_type_labels, 'public' => false ) ); } /** * Handle any Add, Edit, or Delete actions from the admin interface * Hooks into admin ajax because it's the proper context for these sort of actions * * @since 0.2 */ function handle_admin_action() { if ( !wp_verify_nonce( $_REQUEST['nonce'], 'acm-admin-action' ) ) wp_die( __( 'Doing something fishy, eh?', 'ad-code-manager' ) ); if ( !current_user_can( $this->manage_ads_cap ) ) wp_die( __( 'You do not have the necessary permissions to perform this action', 'ad-code-manager' ) ); // Depending on the method we're performing, sanitize the requisite data and do it switch( $_REQUEST['method'] ) { case 'add': case 'edit': $id = ( isset( $_REQUEST['id'] ) ) ? (int)$_REQUEST['id'] : 0; $priority = ( isset( $_REQUEST['priority'] ) ) ? (int)$_REQUEST['priority'] : 10; $ad_code_vals = array( 'priority' => $priority, ); foreach( $this->current_provider->columns as $slug => $title ) { $ad_code_vals[$slug] = sanitize_text_field( $_REQUEST['acm-column'][$slug] ); } if ( $_REQUEST['method'] == 'add') $id = $this->create_ad_code( $ad_code_vals ); else $id = $this->edit_ad_code( $id, $ad_code_vals ); if ( is_wp_error( $id ) ) { $message = 'error-adding-editing-ad-code'; break; } $new_conditionals = array(); $unsafe_conditionals = ( isset( $_REQUEST['acm-conditionals'] ) ) ? $_REQUEST['acm-conditionals'] : array(); foreach( $unsafe_conditionals as $index => $unsafe_conditional ) { $index = (int)$index; $arguments = ( isset( $_REQUEST['acm-arguments'][$index] ) ) ? sanitize_text_field( $_REQUEST['acm-arguments'][$index] ) : ''; $conditional = array( 'function' => sanitize_key( $unsafe_conditional ), 'arguments' => $arguments, ); if ( !empty( $conditional['function'] ) ) { $new_conditionals[] = $conditional; } } if ( $_REQUEST['method'] == 'add' ) { foreach( $new_conditionals as $new_conditional ) { $this->create_conditional( $id, $new_conditional ); } $message = 'ad-code-added'; } else { $this->edit_conditionals( $id, $new_conditionals ); $message = 'ad-code-updated'; } $this->flush_cache(); break; case 'delete': $id = (int)$_REQUEST['id']; $this->delete_ad_code( $id ); $this->flush_cache(); $message = 'ad-code-deleted'; break; } if ( isset( $_REQUEST['doing_ajax'] ) && $_REQUEST['doing_ajax'] ){ switch( $_REQUEST['method'] ) { case 'edit': set_current_screen( 'ad-code-manager' ); $this->wp_list_table = new $this->providers->{$this->current_provider_slug}['table']; $this->wp_list_table->prepare_items(); $new_ad_code = $this->get_ad_code( $id ); echo $this->wp_list_table->single_row( $new_ad_code ); break; } } else { // @todo support ajax and non-ajax requests $redirect_url = add_query_arg( 'message', $message, remove_query_arg( 'message', wp_get_referer() ) ); wp_safe_redirect( $redirect_url ); } exit; } /** * Get the ad codes stored in our custom post type * */ function get_ad_codes( $query_args = array() ) { $ad_codes_formatted = array(); $allowed_query_params = apply_filters( 'acm_allowed_get_posts_args', array( 'offset' ) ); /** * Configuration filter: acm_ad_code_count * * By default we limit query to 50 ad codes * Use this filter to change limit */ $args = array( 'post_type' => $this->post_type, 'numberposts' => apply_filters( 'acm_ad_code_count', 50 ), ); foreach ( (array) $query_args as $query_key => $query_value ) { if ( ! in_array( $query_key, $allowed_query_params ) ) { unset( $query_args[$query_key] ); } else { $args[$query_key] = $query_value; } } if ( false === ( $ad_codes_formatted = wp_cache_get( 'ad_codes' , 'acm' ) ) ) { $ad_codes = get_posts( $args ); foreach ( $ad_codes as $ad_code_cpt ) { $provider_url_vars = array(); foreach ( $this->current_provider->columns as $slug => $title ) { $provider_url_vars[$slug] = get_post_meta( $ad_code_cpt->ID, $slug, true ); } $priority = get_post_meta( $ad_code_cpt->ID, 'priority', true ); $priority = ( !empty( $priority ) ) ? intval( $priority ) : 10; $ad_codes_formatted[] = array( 'conditionals' => $this->get_conditionals( $ad_code_cpt->ID ), 'url_vars' => $provider_url_vars, 'priority' => $priority, 'post_id' => $ad_code_cpt->ID ); } wp_cache_add( 'ad_codes', $ad_codes_formatted, 'acm', 3600 ); } return $ad_codes_formatted; } /** * Get a single ad code * * @param int $post_id Post ID for the ad code that we want * @return array $ad_code Ad code representation of the data */ function get_ad_code( $post_id ) { $post = get_post( $post_id ); if ( !$post ) return false; $provider_url_vars = array(); foreach ( $this->current_provider->columns as $slug => $title ) { $provider_url_vars[$slug] = get_post_meta( $post->ID, $slug, true ); } $priority = get_post_meta( $post_id, 'priority', true ); $priority = ( !empty( $priority ) ) ? intval( $priority ) : 10; $ad_code_formatted = array( 'conditionals' => $this->get_conditionals( $post->ID ), 'url_vars' => $provider_url_vars, 'priority' => $priority, 'post_id' => $post->ID ); return $ad_code_formatted; } /** * Flush cache */ function flush_cache() { wp_cache_delete('ad_codes', 'acm' ); } /** * Get the conditional values for an ad code */ function get_conditionals( $ad_code_id ) { $conditionals = get_post_meta( $ad_code_id, 'conditionals', true ); if ( empty( $conditionals ) ) $conditionals = array(); return $conditionals; } /** * Create a new ad code in the database * * @uses register_ad_code() * * @param array $ad_code * * @return int|false post_id or false */ function create_ad_code( $ad_code = array() ) { $titles = array(); foreach ( $this->current_provider->columns as $slug => $col_title ) { // We shouldn't create an ad code, // If any of required fields is not set if ( ! $ad_code[$slug] ) { return; } $titles[] = $ad_code[$slug]; } $acm_post = array( 'post_title' => implode( '-', $titles ), 'post_status' => 'publish', 'comment_status' => 'closed', 'ping_status' => 'closed', 'post_type' => $this->post_type, ); if ( ! is_wp_error( $acm_inserted_post_id = wp_insert_post( $acm_post, true ) ) ) { foreach ( $this->current_provider->columns as $slug => $title ) { update_post_meta( $acm_inserted_post_id, $slug, $ad_code[$slug] ); } update_post_meta( $acm_inserted_post_id, 'priority', $ad_code['priority'] ); $this->flush_cache(); return $acm_inserted_post_id; } return false; } /** * Update an existing ad code */ function edit_ad_code( $ad_code_id, $ad_code = array()) { foreach ( $this->current_provider->columns as $slug => $title ) { // We shouldn't update an ad code, // If any of required fields is not set if ( ! $ad_code[$slug] ) { return new WP_Error(); } } if ( 0 !== $ad_code_id ) { foreach ( $this->current_provider->columns as $slug => $title ) { update_post_meta( $ad_code_id, $slug, $ad_code[$slug] ); } update_post_meta( $ad_code_id, 'priority', $ad_code['priority'] ); } $this->flush_cache(); return $ad_code_id; } /** * Delete an existing ad code */ function delete_ad_code( $ad_code_id ) { if ( 0 !== $ad_code_id ) { wp_delete_post( $ad_code_id , true ); //force delete post $this->flush_cache(); return true; } return; } /** * Create conditional * * @param int $ad_code_id id of our CPT post * @param array $conditional to add * * @return bool */ function create_conditional( $ad_code_id, $conditional ) { if ( 0 !== $ad_code_id && !empty( $conditional ) ) { $existing_conditionals = get_post_meta( $ad_code_id, 'conditionals', true ); if ( ! is_array( $existing_conditionals ) ) { $existing_conditionals = array(); } $existing_conditionals[] = array( 'function' => $conditional['function'], 'arguments' => explode(';', $conditional['arguments'] ), ); return update_post_meta( $ad_code_id, 'conditionals', $existing_conditionals ); } return false; } /** * Update all conditionals for ad code * * @param int $ad_code_id id of our CPT post * @param array of $conditionals * * @since v0.2 * @return bool */ function edit_conditionals( $ad_code_id, $conditionals = array() ) { if ( 0 !== $ad_code_id && !empty( $conditionals ) ) { $new_conditionals = array(); foreach( $conditionals as $conditional ) { if ( '' == $conditional['function'] ) continue; $new_conditionals[] = array( 'function' => $conditional['function'], 'arguments' => (array) $conditional['arguments'], ); } return update_post_meta( $ad_code_id, 'conditionals', $new_conditionals ); } elseif ( 0 !== $ad_code_id ) { return update_post_meta( $ad_code_id, 'conditionals', array() ); } } /** * Print our vars as JS */ function post_admin_header() { if ( !isset( $_GET['page'] ) || $_GET['page'] != $this->plugin_slug ) return; $conditionals_parsed = array(); foreach ( $this->whitelisted_conditionals as $conditional ) $conditionals_parsed[] = $conditional . ':' . ucfirst( str_replace('_', ' ', $conditional ) ); ?> title, $this->title, $this->manage_ads_cap, $this->plugin_slug, array( $this, 'admin_view_controller' ) ); add_action( 'load-' . $hook, array( $this, 'action_load_ad_code_manager' ) ); } /** * Instantiate the List Table and handle our bulk actions on the load of the page * * @since 0.2.2 */ function action_load_ad_code_manager() { // Instantiate this list table $this->wp_list_table = new $this->providers->{$this->current_provider_slug}['table']; // Handle any bulk action requests switch( $this->wp_list_table->current_action() ) { case 'delete': check_admin_referer( 'acm-bulk-action', 'bulk-action-nonce' ); $ad_code_ids = array_map( 'intval', $_REQUEST['ad-codes'] ); foreach( $ad_code_ids as $ad_code_id ) { $this->delete_ad_code( $ad_code_id ); } $redirect_url = add_query_arg( 'message', 'ad-codes-deleted', remove_query_arg( 'message', wp_get_referer() ) ); wp_safe_redirect( $redirect_url ); exit; } } /** * Print the admin interface for managing the ad codes * */ function admin_view_controller() { require_once( AD_CODE_MANAGER_ROOT . '/common/views/ad-code-manager.tpl.php' ); } function parse_readme_into_contextual_help() { ob_start(); include_once(AD_CODE_MANAGER_ROOT . '/readme.txt' ); $readme = ob_get_clean(); $sections = preg_split( "/==(.*)==/", $readme ); // Something's wrong with readme, fail silently if ( 5 > count( $sections) ) return; $useful = array( $sections[3], $sections[2], $sections[4] ); foreach ( $useful as $i => $tab ) { // Because WP.ORG Markdown has a different flavor $useful[$i] = Markdown( str_replace(array('= ', ' ='), '**', $tab ) ); } return $useful; } function contextual_help() { global $pagenow; if ( 'tools.php' != $pagenow || !isset( $_GET['page'] ) || $_GET['page'] != $this->plugin_slug ) return; list( $installation, $description, $configuration ) = $this->parse_readme_into_contextual_help(); ob_start(); ?>
Note: this is not full list of conditional tags, you can always check out Codex page.