-
- register_breakpoint($identifer,$args)](#doubleclick-register_breakpointidentiferargs)
- * [$DoubleClick->place_ad($identifer,$size,$breakpoints)](#doubleclick-place_adidentifersizebreakpoints)
-
-* * *
-
-## 1. Define Breakpoints
-
-##### $DoubleClick->register_breakpoint($identifer,$args)
-
-You can make it easier for users to target breakpoints by defining them in `functions.php`
-
-##### Example:
-
-```php
-function ad_setup() {
-
- global $DoubleClick;
-
- // Optionally define the network code directly in functions.php.
- // $DoubleClick->networkCode = "xxxxxxx";
-
- /* Define Breakpoints */
- $DoubleClick->register_breakpoint('phone', array('minWidth'=> 0,'maxWidth'=>720));
- $DoubleClick->register_breakpoint('tablet', array('minWidth'=>760,'maxWidth'=>1040));
- $DoubleClick->register_breakpoint('desktop', array('minWidth'=>1040,'maxWidth'=>1220));
- $DoubleClick->register_breakpoint('xl', array('minWidth'=>1220,'maxWidth'=>9999));
-
-}
-add_action('dfw_setup','ad_setup');
-```
-
-##### Paramaters:
-
-__$identifer__
-
-`String` A unique identifier for this breakpoint
-
-__$args__
-
-`Array` An array of properties about the breakpoint. Currently the only keys supported are minWidth and maxWidth.
-
-* * *
-
-## 2. Place Ads
-
-### $DoubleClick->place_ad($identifer,$sizes,$args)
-
-Prints DOM to display an ad at the given breakpoint.
-
-##### Example:
-
-```php
-
-global $DoubleClick;
-
-// simple call:
-$DoubleClick->place_ad('my-identifer','300x250');
-
-// more options:
-$sizes = array(
- 'phone' => '300x50' // show a medium rectangle for phone and up.
- 'tablet' => '728x90' // show a leaderboard for tablet and up.
- 'desktop' => '' // show no ad for desktop and up.
- );
-$args = array(
- 'lazyLoad' => false // if set to true, the ad will load only once its within view on screen.
- );
-
-$DoubleClick->place_ad('my-identifier',$sizes,$args);
-```
-
-
-##### Paramaters:
-
-__$identifer__
-
-`String` The DFP identifier for an ad unit (DFP does not require you to create an identifier. If this does not match a value defined in DFP, a network-wide ad will still be requested).
-
-__$sizes__
-
-`Array|String` The size for the ad. Either a string for all breakpoints, or an array of sizes for each breakpoint.
-
-__$args__
-
-`Array` (optional) An array of additional arguments. Values:
-
- - __lazyLoad__: (true/false) setting this to true and the ad will be loaded only once it's within view on the page. Default is false.
-
-* * *
-
-## 3. Troubleshooting
-
-On any page with DoubleClick ads enabled (namely with DoubleClick js enqueued), load the included developer console to confirm data about advertisement delivery for each placement.
-
-#### Append the URL with the parameter:
-```
-?google_force_console
-```
diff --git a/docs/Targeting.md b/docs/Targeting.md
deleted file mode 100644
index 437202a..0000000
--- a/docs/Targeting.md
+++ /dev/null
@@ -1,91 +0,0 @@
-# Targeting
-
-This plugin implements advanced DFP targeting criteria to allow trafficers to specify pages or groups of pages where line items should serve.
-
-* * *
-
-## 1. Example
-
-A local restaurant might wish to only have their ads shown a landing page and related article pages for a publisher's food category.
-
-
-
-_In the above example, this line item is targeting all posts in the Category "food"._
-
-* * *
-
-## 2. Available targeting criteria
-
-The following WordPress and general targeting criteria are defined for each ad call:
-
-#### WordPress Targeting —
-
-Targeting criteria specific to WordPress variables.
-
- - `Page` → Target the [type of page](http://codex.wordpress.org/Conditional_Tags).
-
- > Takes the values of 'home', 'front-page', 'admin', 'admin-bar-showing', 'single', 'archive', 'author', 'date' or 'search'.
-
- - `Category` → On single pages, target based on WordPress category. The value(s) passed are the WordPress slug for the category.
-
- >
-
- - `Tag` → On single pages, target based on WordPress tags. The value(s) passed are the WordPress slug for the tag.
-
-#### URL Targeting —
-
-Additional targeting criteria set by the URL of the page.
-
- - `inURL` → Target a piece of the page path.
-
- > __eg__. targeting the string '__/dvds__' would match [example.com**/dvds**/](http://example.com/dvds/), [example.com**/dvds**/page1](http://example.com/dvds/page1) and [example.com**/dvds**/page2](http://example.com/dvds/page2)
-
- - `URLIs` → Target the entire page path.
-
- > __eg__. targeting the string '__/books__' will **only** match [example.com**/books**](http://example.com/books/) and not [example.com**/books/page1**](http://example.com/books/page1). (Note: Any trailing '/' is removed.)
-
- - `Domain` → Target based on the domain.
-
- > eg. run different advertising on [staging.example.com](http://staging.example.com) and [example.com](http://example.com).
-
- - `Query` → Target a ?query var.
-
- > eg. target the url [example.com/?**movie=12**](http://example.com/news/) with the targeting string 'p:12'
-
-__Warning__: Targeting strings are limited to 40 characters long by DFP. Targeting URLIs or domains longer than that will result in error.
-
-* * *
-
-## 3. Defining targeting criteria in DFP
-
-DFP needs to be told what filter keys exist before they can be used.
-
-#### Example
-
-In Inventory > Custom Targeting, hit "New Key,"
-
-
-
-Enter a name for the key and "values type" to indicate whether this key is static or dynamic.
-
-For the purposes of this tutorial, we will use the `Category` targeting key. Also for our purposes, we will assume the site has a small number of predefined categories, such as "sports", "arts", "news" and "opinion". This is better suited for a value type of _"Users will select from predefined targeting values"_ (__static__).
-
-
-
-If a key is more __dynamic__, such as a blog that uses hundreds of categories, "values type" should be set it _"Users will enter targeting values when creating line items or checking inventory"_
-
-On the next screen enter values the key could take. This will be a list of categories, unique domains, url segments, tags, &c.
-
-
-
-#### Using the targeting criteria
-
-Now, when creating a line item, select "custom criteria" from the left hand menu under targeting. After entering a targeting key, select one or more options:
-
-
-
-This line item will show only on article pages that belong in the news category.
-
-The [available targeting criteria](#2-available-targeting-criteria) section above contains more information about what is possible with different criteria.
-
-
diff --git a/docs/index.md b/docs/index.md
deleted file mode 100644
index 12831d5..0000000
--- a/docs/index.md
+++ /dev/null
@@ -1,51 +0,0 @@
-#  DoubleClick for WordPress
-
-Serve DoubleClick ads natively in WordPress. Built to make serving responsive ads easy.
-
-Built by the [Institute for Nonprofit News](http://inn.org/), DoubleClick for WordPress works with [Project Largo](http://largoproject.org/) or any standalone WordPress blog.
-
-* * *
-
-## 1. What is this thing?
-
-This WordPress plugin serves inventory from a DoubleClick for Publisher account on a WordPress site.
-
-No need to copy and paste ad codes or header tags — the plugin generates all of this on its own.
-
-* * *
-
-## 2. How do I use it?
-
-For the most basic integration, only two steps are necessary.
-
-#### __2.1. Define Settings__ —
-
-Under _Settings > DoubleClick for WordPress_ update the field with your network code from DFP, and a place to define breakpoints to serve ads to.
-
-**NOTE:** Both Network Code and Breakpoints may be defined by a developer within the WordPress theme. If a developer already defined these values within the theme, a user will know based on their display in the plugin Settings page.
-
-
-
-#### __2.2 Placing Advertisements__ —
-
-Advertisements are placed in two ways.
-
-##### 1. Via Reusable Widget
-
-
-
- * The __identifier__ field is the name of a line item in DoubleClick for Publishers. If an line item with the same identifier in DoubleClick matches the identifier set in the widget, the ad will load (subject to conditional targeting set in DFP admin). If the identifier is blank or doesn't match a line item in DFP, the plugin attempts to load inventory from anywhere in the DFP account.
-
- * Based on breakpoints defined in plugin settings or theme, an __Inventory Size__ can be defined for each breakpoint set either in the plugin settings or via theme function.
- * For an ad the same __Inventory Size__ at every breakpoint, use that size in each breakpoint (i.e. `300x250`).
- * For an ad with multiple __Inventory Sizes__ (and corresponding creatives), define the appropriate Inventory Size for each breakpoint (i.e. `320x50` for a mobile breakpoint, `728x90` for tablet and desktop breakpoints).
-
-* * *
-
-##### 2. Via Theme Function
-
-See [Developer API](Developer-API.md) documentation.
-
-## 3. Is that it?
-
-Nope! Next [configure targeting](Targeting.md) and advanced users may look at the [developer api](developer-api/).
diff --git a/doubleclick-for-wordpress.php b/doubleclick-for-wordpress.php
new file mode 100644
index 0000000..e1032de
--- /dev/null
+++ b/doubleclick-for-wordpress.php
@@ -0,0 +1,366 @@
+basename = plugin_basename( __FILE__ );
+ $this->url = plugin_dir_url( __FILE__ );
+ $this->path = plugin_dir_path( __FILE__ );
+ }
+
+ /**
+ * Attach other plugin classes to the base plugin class.
+ *
+ * @since 0.2.1
+ */
+ public function plugin_classes() {
+ global $doubleclick;
+ $this->options = new DCWP_Options( $this );
+ $this->widget = new DCWP_Widget( $this );
+ $doubleclick = new DCWP_DoubleClick( $this );
+ } // END OF PLUGIN CLASSES FUNCTION
+
+ /**
+ * Add hooks and filters.
+ * Priority needs to be
+ * < 10 for CPT_Core,
+ * < 5 for Taxonomy_Core,
+ * and 0 for Widgets because widgets_init runs at init priority 1.
+ *
+ * @since 0.2.1
+ */
+ public function hooks() {
+ add_action( 'init', array( $this, 'init' ), 0 );
+ do_action( 'dfw_setup' );
+ }
+
+ /**
+ * Activate the plugin.
+ *
+ * @since 0.2.1
+ */
+ public function _activate() {
+ // Bail early if requirements aren't met.
+ if ( ! $this->check_requirements() ) {
+ return;
+ }
+
+ // Make sure any rewrite functionality has been loaded.
+ flush_rewrite_rules();
+ }
+
+ /**
+ * Deactivate the plugin.
+ * Uninstall routines should be in uninstall.php.
+ *
+ * @since 0.2.1
+ */
+ public function _deactivate() {
+ // Add deactivation cleanup functionality here.
+ }
+
+ /**
+ * Init hooks
+ *
+ * @since 0.2.1
+ */
+ public function init() {
+ // Bail early if requirements aren't met.
+ if ( ! $this->check_requirements() ) {
+ return;
+ }
+
+ // Load translated strings for plugin.
+ load_plugin_textdomain( 'dfw', false, dirname( $this->basename ) . '/languages/' );
+
+ // Run the updates if needed.
+ $this->update_options();
+
+ // Load the includes.
+ $this->load_files();
+
+ // Initialize plugin classes.
+ $this->plugin_classes();
+
+ // Add a settings link to the plugins page.
+ add_filter( 'plugin_action_links_' . $this->basename, array( 'DCWP_Options', 'add_settings_link' ) );
+
+ }
+
+ /**
+ * Check if the plugin meets requirements and
+ * disable it if they are not present.
+ *
+ * @since 0.2.1
+ *
+ * @return boolean True if requirements met, false if not.
+ */
+ public function check_requirements() {
+
+ // Bail early if plugin meets requirements.
+ if ( $this->meets_requirements() ) {
+ return true;
+ }
+
+ // Add a dashboard notice.
+ add_action( 'all_admin_notices', array( $this, 'requirements_not_met_notice' ) );
+
+ // Deactivate our plugin.
+ add_action( 'admin_init', array( $this, 'deactivate_me' ) );
+
+ // Didn't meet the requirements.
+ return false;
+ }
+
+ /**
+ * Before v0.3 the options were not prefixed.
+ * Here, we update the option keys if needed.
+ *
+ * @since 0.3
+ */
+ public function update_options() {
+ $prefix = 'dfw_';
+ $options = array( 'network_code', 'breakpoints' );
+ foreach ( $options as $old_option ) {
+ $new_option = $prefix . $old_option;
+ if ( ! get_option( $new_option ) && $old_option_value = get_option( $old_option ) ) {
+ update_option( $new_option, $old_option_value );
+ delete_option( $old_option );
+ }
+ }
+ }
+
+ /**
+ * Load all of the stuff in the includes folder.
+ *
+ * @since 0.3
+ */
+ public function load_files() {
+ $includes = array(
+ 'includes/class-breakpoint.php',
+ 'includes/class-ad-slot.php',
+ 'includes/class-options.php',
+ 'includes/class-widget.php',
+ 'includes/class-doubleclick.php',
+ );
+
+ foreach ( $includes as $include ) {
+ if ( 0 === validate_file( $this->path . $include ) ) {
+ require_once( $this->path . $include );
+ }
+ }
+ }
+
+ /**
+ * Deactivates this plugin, hook this function on admin_init.
+ *
+ * @since 0.2.1
+ */
+ public function deactivate_me() {
+
+ // We do a check for deactivate_plugins before calling it, to protect
+ // any developers from accidentally calling it too early and breaking things.
+ if ( function_exists( 'deactivate_plugins' ) ) {
+ deactivate_plugins( $this->basename );
+ }
+ }
+
+ /**
+ * Check that all plugin requirements are met.
+ *
+ * @since 0.2.1
+ *
+ * @return boolean True if requirements are met.
+ */
+ public function meets_requirements() {
+
+ // Do checks for required classes / functions or similar.
+ // Add detailed messages to $this->activation_errors array.
+ return true;
+ }
+
+ /**
+ * Adds a notice to the dashboard if the plugin requirements are not met.
+ *
+ * @since 0.2.1
+ */
+ public function requirements_not_met_notice() {
+
+ // Compile default message.
+ $default_message = sprintf( __( 'DoubleClick for WordPress is missing requirements and has been deactivated. Please make sure all requirements are available.', 'doubleclick-for-wordpress' ), admin_url( 'plugins.php' ) );
+
+ // Default details to null.
+ $details = null;
+
+ // Add details if any exist.
+ if ( $this->activation_errors && is_array( $this->activation_errors ) ) {
+ $details = '' . implode( ' ', $this->activation_errors ) . '';
+ }
+
+ // Output errors.
+ ?>
+
+
+
+
+ $field;
+ default:
+ throw new Exception( 'Invalid ' . __CLASS__ . ' property: ' . $field );
+ }
+ }
+}
+
+/**
+ * Grab the DoubleClick_For_WordPress object and return it.
+ * Wrapper for DoubleClick_For_WordPress::get_instance().
+ *
+ * @since 0.2.1
+ * @return DoubleClick_For_WordPress Singleton instance of plugin class.
+ */
+function doubleclick_for_wordpress() {
+ return DoubleClick_For_WordPress::get_instance();
+}
+
+// Kick it off.
+add_action( 'plugins_loaded', array( doubleclick_for_wordpress(), 'hooks' ) );
+
+// Activation and deactivation.
+register_activation_hook( __FILE__, array( doubleclick_for_wordpress(), '_activate' ) );
+register_deactivation_hook( __FILE__, array( doubleclick_for_wordpress(), '_deactivate' ) );
diff --git a/includes/README.md b/includes/README.md
new file mode 100644
index 0000000..0d7a1a6
--- /dev/null
+++ b/includes/README.md
@@ -0,0 +1,6 @@
+# DoubleClick for WordPress Includes #
+https://labs.inn.org
+Copyright (c) 2017 innlabs, willhaynes24
+Licensed under the GPLv2 license.
+
+Additional PHP functionality goes here.
\ No newline at end of file
diff --git a/includes/class-ad-slot.php b/includes/class-ad-slot.php
new file mode 100644
index 0000000..26016a6
--- /dev/null
+++ b/includes/class-ad-slot.php
@@ -0,0 +1,124 @@
+identifier = str_replace('/','//',$identifier);
+ */
+ $this->identifier = $identifer;
+ $this->sizes = $size;
+ $this->id = ++ DCWP_DoubleClick::$count;
+ }
+
+ /**
+ * @TODO need a docbloc for this function
+ */
+ public function breakpoint_identifier() {
+ return null;
+ }
+
+ /**
+ * If this ad unit has a size mapping.
+ */
+ public function has_mapping() {
+ if ( is_string( $this->sizes ) ) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * @TODO need a docblock for this function
+ */
+ public function mapping() {
+ global $doubleclick;
+
+ // Return false if there is no mapping.
+ if ( ! $this->has_mapping() ) {
+ return false;
+ }
+
+ $mapping = array();
+
+ if ( empty( $this->sizes ) ) {
+ return $mapping;
+ }
+
+ foreach ( $this->sizes as $breakpoint_identifier => $size ) {
+ $breakpoint = $doubleclick->breakpoints[ $breakpoint_identifier ];
+
+ // The minimum browser width/height for this sizemapping.
+ $browser_height = 1;
+ $browser_width = (int) $breakpoint->min_width;
+
+ // Remove any extra spaces in the list of sizes.
+ // (needs to be just a comma-separated list of values).
+ $size = str_replace( ' ', '', $size );
+
+ // eg. 300x250,336x300.
+ $size_strings = explode( ',', $size );
+ $size_array = array();
+
+ foreach ( $size_strings as $size ) {
+ if ( ! empty( $size ) ) {
+ $arr = explode( 'x', $size ); // eg. 300x250.
+ $width = (int) $arr[0];
+ $height = (int) $arr[1];
+ $size_array[] = array( $width, $height );
+ }
+ }
+
+ $mapping[] = array(
+ 'browser' => array( $browser_width, $browser_height ),
+ 'ad_sizes' => $size_array,
+ );
+ }
+
+ return $mapping;
+ }
+}
diff --git a/includes/class-breakpoint.php b/includes/class-breakpoint.php
new file mode 100644
index 0000000..73cf180
--- /dev/null
+++ b/includes/class-breakpoint.php
@@ -0,0 +1,82 @@
+min_width = $args['min_width'];
+ }
+
+ if ( isset( $args['max_width'] ) ) {
+ $this->max_width = $args['max_width'];
+ }
+
+ if ( isset( $args['_option'] ) && $args['_option'] ) {
+ $this->option = true;
+ }
+
+ $this->identifier = $identifier;
+ }
+
+ /**
+ * Prints a javascript boolean statement for this breakpoint
+ */
+ public function js_logic() {
+ echo wp_json_encode( $this->get_js_logic() );
+ }
+
+ /**
+ * Returns a string with the boolean logic for the breakpoint.
+ *
+ * @return String boolean logic for breakpoint.
+ */
+ public function get_js_logic() {
+ return "($this->min_width <= document.documentElement.clientWidth && document.documentElement.clientWidth < $this->max_width)";
+ }
+}
diff --git a/dfw-init.php b/includes/class-doubleclick.php
similarity index 52%
rename from dfw-init.php
rename to includes/class-doubleclick.php
index e8aa577..b3ffa6b 100644
--- a/dfw-init.php
+++ b/includes/class-doubleclick.php
@@ -1,34 +1,25 @@
network_code = $network_code;
+ $this->network_code = $this->network_code();
// Script enqueue is static because we only ever want to print it once.
if ( ! $this::$enqueued ) {
@@ -99,19 +91,22 @@ public function __construct( $network_code = null ) {
add_action( 'wp_print_footer_scripts', array( $this, 'footer_script' ) );
- $breakpoints = maybe_unserialize( get_option( 'dfw_breakpoints' ) );
+ $breakpoints = apply_filters( 'dfw_breakpoints', maybe_unserialize( get_option( 'dfw_breakpoints' ) ) );
- if ( ! empty( $breakpoints ) ) :
+ if ( ! empty( $breakpoints ) ) {
foreach ( $breakpoints as $breakpoint ) {
+ // if this is not set explicitly, it's coming from the dfw_breakpoints option.
+ if ( ! isset( $breakpoint['option'] ) ) {
+ $breakpoint['option'] = true;
+ }
$args = array(
'min_width' => $breakpoint['min-width'],
'max_width' => $breakpoint['max-width'],
- '_option' => true,// this breakpoint is set in WordPress options.
- );
+ '_option' => $breakpoint['option'],
+ );
$this->register_breakpoint( $breakpoint['identifier'], $args );
}
- endif;
-
+ }
}
/**
@@ -121,7 +116,7 @@ public function __construct( $network_code = null ) {
* @param string|array $args additional args.
*/
public function register_breakpoint( $identifier, $args = null ) {
- $this->breakpoints[ $identifier ] = new DoubleClickBreakpoint( $identifier, $args );
+ $this->breakpoints[ $identifier ] = new DCWP_Breakpoint( $identifier, $args );
}
/**
@@ -134,16 +129,16 @@ public function enqueue_scripts() {
wp_register_script(
'jquery.dfp.js',
- plugins_url( 'js/vendor/jquery.dfp.js/jquery.dfp' . $suffix . '.js', __FILE__ ),
+ plugins_url( 'assets/js/jquery.dfp' . $suffix . '.js', dirname( __FILE__ ) ),
array( 'jquery' ),
- DFP_VERSION,
+ DoubleClick_For_WordPress::VERSION,
true
);
wp_register_script(
'jquery.dfw.js',
- plugins_url( 'js/jquery.dfw.js', __FILE__ ),
+ plugins_url( 'assets/js/jquery.dfw' . $suffix . '.js', dirname( __FILE__ ) ),
array( 'jquery.dfp.js' ),
- DFP_VERSION,
+ DoubleClick_For_WordPress::VERSION,
true
);
@@ -165,13 +160,15 @@ public function enqueue_scripts() {
wp_localize_script( 'jquery.dfw.js', 'dfw', $data );
wp_enqueue_script( 'jquery.dfw.js' );
- wp_enqueue_style(
- 'dfp',
- plugins_url( 'css/dfp.css', __FILE__ ),
- array(),
- DFP_VERSION,
- 'all'
- );
+ if ( ! empty( get_option( 'dfw_css' ) ) ) {
+ wp_enqueue_style(
+ 'dfp',
+ plugins_url( 'assets/css/dfp.css', dirname( __FILE__ ) ),
+ array(),
+ DoubleClick_For_WordPress::VERSION,
+ 'all'
+ );
+ }
}
/**
@@ -181,9 +178,13 @@ public function enqueue_scripts() {
* @return String network code.
*/
private function network_code() {
- return isset( $this->network_code ) ? $this->network_code : get_option( 'dfw_network_code','xxxxxx' );
+ $network_code = isset( $this->network_code ) ? $this->network_code : get_option( 'dfw_network_code' );
+ return apply_filters( 'dfw_network_code', $network_code );
}
+ /**
+ * Add DFP script to the footer
+ */
public function footer_script() {
if ( ! $this->debug ) {
$mappings = array();
@@ -194,7 +195,7 @@ public function footer_script() {
} ?>
-
-
-
-
-
-
-
-
-
-