Easy Digital Downloads
  • Package
  • Class
  • Tree

Packages

  • EDD
    • Admin
      • Actions
      • Add-ons
      • Dashboard
      • Discounts
      • Downloads
      • Export
      • Notices
      • Pages
      • Payments
      • Reports
      • Settings
      • System
      • Upgrades
      • Upload
      • Welcome
    • Cart
    • Checkout
    • Classes
      • API
      • Fees
      • HTML
      • Roles
      • Session
    • Emails
    • Functions
      • AJAX
      • Compatibility
      • Errors
      • Formatting
      • Install
      • Login
      • Taxes
      • Templates
    • Gateways
    • Logging
    • Payments
    • Shortcodes
    • Widgets

Classes

  • EDD_API
   1 <?php
   2 /**
   3  * Easy Digital Downloads API
   4  *
   5  * This class provides a front-facing JSON/XML API that makes it possible to
   6  * query data from the shop.
   7  *
   8  * The primary purpose of this class is for external sales / earnings tracking
   9  * systems, such as mobile. This class is also used in the EDD iOS App.
  10  *
  11  * @package     EDD
  12  * @subpackage  Classes/API
  13  * @copyright   Copyright (c) 2013, Pippin Williamson
  14  * @license     http://opensource.org/licenses/gpl-2.0.php GNU Public License
  15  * @since       1.5
  16  */
  17 
  18 // Exit if accessed directly
  19 if ( ! defined( 'ABSPATH' ) ) exit;
  20 
  21 /**
  22  * EDD_API Class
  23  *
  24  * Renders API returns as a JSON/XML array
  25  *
  26  * @since  1.5
  27  */
  28 class EDD_API {
  29     /**
  30      * Pretty Print?
  31      *
  32      * @var bool
  33      * @access private
  34      * @since 1.5
  35      */
  36     private $pretty_print = false;
  37 
  38     /**
  39      * Log API requests?
  40      *
  41      * @var bool
  42      * @access private
  43      * @since 1.5
  44      */
  45     private $log_requests = true;
  46 
  47     /**
  48      * Is this a valid request?
  49      *
  50      * @var bool 
  51      * @access private
  52      * @since 1.5
  53      */
  54     private $is_valid_request = false;
  55 
  56     /**
  57      * User ID Performing the API Request
  58      *
  59      * @var int
  60      * @access private
  61      * @since 1.5.1
  62      */
  63     private $user_id = 0;
  64 
  65     /**
  66      * Setup the EDD API
  67      *
  68      * @access public
  69      * @author Daniel J Griffiths
  70      * @since 1.5
  71      * @return void
  72      */
  73     public function __construct() {
  74         add_action( 'init',                    array( $this, 'add_endpoint'   ) );
  75         add_action( 'template_redirect',       array( $this, 'process_query'  ), -1 );
  76         add_filter( 'query_vars',              array( $this, 'query_vars'     ) );
  77         add_action( 'show_user_profile',       array( $this, 'user_key_field' ) );
  78         add_action( 'personal_options_update', array( $this, 'update_key'     ) );
  79 
  80         // Determine if JSON_PRETTY_PRINT is available
  81         $this->pretty_print = defined( 'JSON_PRETTY_PRINT' ) ? JSON_PRETTY_PRINT : null;
  82 
  83         // Allow API request logging to be turned off
  84         $this->log_requests = apply_filters( 'edd_api_log_requests', $this->log_requests );
  85     }
  86 
  87     /**
  88      * Registers a new rewrite endpoint for accessing the API
  89      *
  90      * @access public
  91      * @author Daniel J Griffiths
  92      * @param array $rewrite_rules WordPress Rewrite Rules
  93      * @since 1.5
  94      */
  95     public function add_endpoint( $rewrite_rules ) {
  96         add_rewrite_endpoint( 'edd-api', EP_ALL );
  97     }
  98 
  99     /**
 100      * Registers query vars for API access
 101      *
 102      * @access public
 103      * @since 1.5
 104      * @author Daniel J Griffiths
 105      * @param array $vars Query vars
 106      * @return array $vars New query vars
 107      */
 108     public function query_vars( $vars ) {
 109         $vars[] = 'token';
 110         $vars[] = 'key';
 111         $vars[] = 'query';
 112         $vars[] = 'type';
 113         $vars[] = 'product';
 114         $vars[] = 'number';
 115         $vars[] = 'date';
 116         $vars[] = 'startdate';
 117         $vars[] = 'enddate';
 118         $vars[] = 'customer';
 119         $vars[] = 'format';
 120 
 121         return $vars;
 122     }
 123 
 124     /**
 125      * Validate the API request
 126      *
 127      * Checks for the user's public key and token against the secret key
 128      *
 129      * @access private
 130      * @global object $wp_query WordPress Query
 131      * @uses EDD_API::get_user()
 132      * @uses EDD_API::invalid_key()
 133      * @uses EDD_API::invalid_auth()
 134      * @since 1.5
 135      * @return void
 136      */
 137     private function validate_request() {
 138         global $wp_query;
 139 
 140         // Make sure we have both user and api key
 141         if ( empty( $wp_query->query_vars['token'] ) || empty( $wp_query->query_vars['key'] ) )
 142             $this->missing_auth();
 143 
 144         // Retrieve the user by public API key and ensure they exist
 145         if ( ! ( $user = $this->get_user( $wp_query->query_vars['key'] ) ) ) :
 146             $this->invalid_key( $wp_query->query_vars['key'] );
 147         else :
 148             $token  = urldecode( $wp_query->query_vars['token'] );
 149             $secret = get_user_meta( $user, 'edd_user_secret_key', true );
 150             $public = urldecode( $wp_query->query_vars['key'] );
 151 
 152             if ( hash( 'md5', $secret . $public ) === $token )
 153                 $this->is_valid_request = true;
 154             else
 155                 $this->invalid_auth();
 156         endif;
 157     }
 158 
 159     /**
 160      * Retrieve the user ID based on the public key provided
 161      *
 162      * @access public
 163      * @since 1.5.1
 164      * @global object $wpdb Used to query the database using the WordPress
 165      *   Database API
 166      * @param int $key Public Key
 167      * @return mixed string if user ID is found, false otherwise
 168      */
 169     public function get_user( $key = '' ) {
 170         global $wpdb;
 171 
 172         $user = $wpdb->get_var( $wpdb->prepare( "SELECT user_id FROM $wpdb->usermeta WHERE meta_key = 'edd_user_public_key' AND meta_value = %s LIMIT 1", $key ) );
 173 
 174         if ( $user != NULL ) {
 175             $this->user_id = $user;
 176             return $user;
 177         }
 178         return false;
 179     }
 180 
 181     /**
 182      * Displays a missing authentication error if all the parameters aren't
 183      * provided
 184      *
 185      * @access public
 186      * @author Daniel J Griffiths
 187      * @uses EDD_API::output()
 188      * @since 1.5
 189      */
 190     public function missing_auth() {
 191         $error['error'] = __( 'You must specify both a token and API key!', 'edd' );
 192 
 193         $this->output( $error );
 194     }
 195 
 196     /**
 197      * Displays an authentication failed error if the user failed to provide valid
 198      * credentials
 199      *
 200      * @access public
 201      * @since  1.5
 202      * @uses EDD_API::output()
 203      * @return void
 204      */
 205     function invalid_auth() {
 206         $error['error'] = __( 'Your request could not be authenticated!', 'edd' );
 207 
 208         $this->output( $error );
 209     }
 210 
 211     /**
 212      * Displays an invalid API key error if the API key provided couldn't be
 213      * validated
 214      *
 215      * @access public
 216      * @author Daniel J Griffiths
 217      * @since 1.5
 218      * @uses EDD_API::output()
 219      * @return void
 220      */
 221     function invalid_key() {
 222         $error['error'] = __( 'Invalid API key!', 'edd' );
 223 
 224         $this->output( $error );
 225     }
 226 
 227 
 228     /**
 229      * Listens for the API and then processes the API requests
 230      *
 231      * @access public
 232      * @author Daniel J Griffiths
 233      * @global $wp_query
 234      * @since 1.5
 235      * @return void
 236      */
 237     public function process_query() {
 238         global $wp_query;
 239 
 240         // Check for edd-api var. Get out if not present
 241         if ( ! isset( $wp_query->query_vars['edd-api'] ) )
 242             return;
 243 
 244         // Check for a valid user and set errors if necessary
 245         $this->validate_request();
 246 
 247         // Only proceed if no errors have been noted
 248         if( ! $this->is_valid_request )
 249             return;
 250 
 251         // Determine the kind of query
 252         $query_mode = $this->get_query_mode();
 253 
 254         $data = array();
 255 
 256         switch( $query_mode ) :
 257 
 258             case 'stats' :
 259 
 260                 $data = $this->get_stats( array(
 261                     'type'      => $wp_query->query_vars['type'],
 262                     'product'   => isset( $wp_query->query_vars['product'] )   ? $wp_query->query_vars['product']   : null,
 263                     'date'      => isset( $wp_query->query_vars['date'] )      ? $wp_query->query_vars['date']      : null,
 264                     'startdate' => isset( $wp_query->query_vars['startdate'] ) ? $wp_query->query_vars['startdate'] : null,
 265                     'enddate'   => isset( $wp_query->query_vars['enddate'] )   ? $wp_query->query_vars['enddate']   : null
 266                 ) );
 267 
 268                 break;
 269 
 270             case 'products' :
 271 
 272                 $product = isset( $wp_query->query_vars['product'] )   ? $wp_query->query_vars['product']   : null;
 273 
 274                 $data = $this->get_products( $product );
 275 
 276                 break;
 277 
 278             case 'customers' :
 279 
 280                 $customer = isset( $wp_query->query_vars['customer'] ) ? $wp_query->query_vars['customer']  : null;
 281 
 282                 $data = $this->get_customers( $customer );
 283 
 284                 break;
 285 
 286             case 'sales' :
 287 
 288                 $data = $this->get_recent_sales();
 289 
 290                 break;
 291 
 292         endswitch;
 293 
 294         // Allow extensions to setup their own return data
 295         $data = apply_filters( 'edd_api_output_data', $data, $query_mode, $this );
 296 
 297         // Log this API request, if enabled. We log it here because we have access to errors.
 298         $this->log_request( $data );
 299 
 300         // Send out data to the output function
 301         $this->output( $data );
 302     }
 303 
 304     /**
 305      * Determines the kind of query requested and also ensure it is a valid query
 306      *
 307      * @access private
 308      * @since 1.5
 309      * @global $wp_query
 310      * @return string $query Query mode
 311      */
 312     private function get_query_mode() {
 313         global $wp_query;
 314 
 315         // Whitelist our query options
 316         $accepted = apply_filters( 'edd_api_valid_query_modes', array(
 317             'stats',
 318             'products',
 319             'customers',
 320             'sales'
 321         ) );
 322 
 323         $query = isset( $wp_query->query_vars['edd-api'] ) ? $wp_query->query_vars['edd-api'] : null;
 324 
 325         // Make sure our query is valid
 326         if ( ! in_array( $query, $accepted ) || ( $query == 'stats' && ! isset( $wp_query->query_vars['type'] ) ) ) {
 327             $error['error'] = __( 'Invalid query!', 'edd' );
 328 
 329             $this->output( $error );
 330         }
 331 
 332         return $query;
 333     }
 334 
 335     /**
 336      * Get page number
 337      *
 338      * @access private
 339      * @since 1.5
 340      * @global $wp_query
 341      * @return int $wp_query->query_vars['page'] if page number returned (default: 1)
 342      */
 343     private function get_paged() {
 344         global $wp_query;
 345 
 346         return isset( $wp_query->query_vars['page'] ) ? $wp_query->query_vars['page'] : 1;
 347     }
 348 
 349 
 350     /**
 351      * Number of results to display per page
 352      *
 353      * @access private
 354      * @since 1.5
 355      * @global $wp_query
 356      * @return int $per_page Results to display per page (default: 10)
 357      */
 358     private function per_page() {
 359         global $wp_query;
 360 
 361         $per_page = isset( $wp_query->query_vars['number'] ) ? $wp_query->query_vars['number'] : 10;
 362 
 363         return apply_filters( 'edd_api_results_per_page', $per_page );
 364     }
 365 
 366     /**
 367      * Retrieve the output format
 368      *
 369      * Determines whether results should be displayed in XML or JSON
 370      *
 371      * @access private
 372      * @since 1.5
 373      * @global $wp_query
 374      * @return $format Output format
 375      */
 376     private function get_output_format() {
 377         global $wp_query;
 378 
 379         $format = isset( $wp_query->query_vars['format'] ) ? $wp_query->query_vars['format'] : 'json';
 380 
 381         return apply_filters( 'edd_api_output_format', $format );
 382     }
 383 
 384     /**
 385      * Sets up the dates used to retrieve earnings/sales
 386      *
 387      * @access public
 388      * @since 1.5.1
 389      * @param array $args Arguments to override defaults
 390      * @return array $dates
 391     */
 392     private function get_dates( $args = array() ) {
 393         $dates = array();
 394 
 395         $defaults = array(
 396             'type'      => '',
 397             'product'   => null,
 398             'date'      => null,
 399             'startdate' => null,
 400             'enddate'   => null
 401         );
 402 
 403         $args = wp_parse_args( $args, $defaults );
 404 
 405         if ( 'range' === $args['date'] ) {
 406             $startdate          = strtotime( $args['startdate'] );
 407             $enddate            = strtotime( $args['enddate'] );
 408             $dates['day_start'] = date( 'd', $startdate );
 409             $dates['day_end']   = date( 'd', $enddate );
 410             $dates['m_start']   = date( 'n', $startdate );
 411             $dates['m_end']     = date( 'n', $enddate );
 412             $dates['year']      = date( 'Y', $startdate );
 413             $dates['year_end']  = date( 'Y', $enddate );
 414         } else {
 415             // Modify dates based on predefined ranges
 416             switch ( $args['date'] ) :
 417 
 418                 case 'this_month' :
 419                     $dates['day']       = null;
 420                     $dates['m_start']   = date( 'n' );
 421                     $dates['m_end']     = date( 'n' );
 422                     $dates['year']      = date( 'Y' );
 423                 break;
 424 
 425                 case 'last_month' :
 426                     $dates['day']     = null;
 427                     $dates['m_start'] = date( 'n' ) == 1 ? 12 : date( 'n' ) - 1;
 428                     $dates['m_end']   = $dates['m_start'];
 429                     $dates['year']    = date( 'n' ) == 1 ? date( 'Y' ) - 1 : date( 'Y' );
 430                 break;
 431 
 432                 case 'today' :
 433                     $dates['day']       = date( 'd' );
 434                     $dates['m_start']   = date( 'n' );
 435                     $dates['m_end']     = date( 'n' );
 436                     $dates['year']      = date( 'Y' );
 437                 break;
 438 
 439                 case 'yesterday' :
 440                     $month              = date( 'n' ) == 1 ? 12 : date( 'n' );
 441                     $days_in_month      = cal_days_in_month( CAL_GREGORIAN, $month, date( 'Y' ) );
 442                     $yesterday          = date( 'd' ) == 1 ? $days_in_month : date( 'd' ) - 1;
 443                     $dates['day']       = $yesterday;
 444                     $dates['m_start']   = $month;
 445                     $dates['m_end']     = $month;
 446                     $dates['year']      = $month == 1 && date( 'd' ) == 1 ? date( 'Y' ) - 1 : date( 'Y' );
 447                 break;
 448 
 449                 case 'this_quarter' :
 450                     $month_now = date( 'n' );
 451 
 452                     $dates['day']           = null;
 453 
 454                     if ( $month_now <= 3 ) {
 455 
 456                         $dates['m_start']   = 1;
 457                         $dates['m_end']     = 3;
 458                         $dates['year']      = date( 'Y' );
 459 
 460                     } else if ( $month_now <= 6 ) {
 461 
 462                         $dates['m_start']   = 4;
 463                         $dates['m_end']     = 6;
 464                         $dates['year']      = date( 'Y' );
 465 
 466                     } else if ( $month_now <= 9 ) {
 467 
 468                         $dates['m_start']   = 7;
 469                         $dates['m_end']     = 9;
 470                         $dates['year']      = date( 'Y' );
 471 
 472                     } else {
 473 
 474                         $dates['m_start']   = 10;
 475                         $dates['m_end']     = 12;
 476                         $dates['year']      = date( 'Y' );
 477 
 478                     }
 479                 break;
 480 
 481                 case 'last_quarter' :
 482                     $month_now = date( 'n' );
 483 
 484                     $dates['day']           = null;
 485 
 486                     if ( $month_now <= 3 ) {
 487 
 488                         $dates['m_start']   = 10;
 489                         $dates['m_end']     = 12;
 490                         $dates['year']      = date( 'Y' ) - 1; // Previous year
 491 
 492                     } else if ( $month_now <= 6 ) {
 493 
 494                         $dates['m_start']   = 1;
 495                         $dates['m_end']     = 3;
 496                         $dates['year']      = date( 'Y' );
 497 
 498                     } else if ( $month_now <= 9 ) {
 499 
 500                         $dates['m_start']   = 4;
 501                         $dates['m_end']     = 6;
 502                         $dates['year']      = date( 'Y' );
 503 
 504                     } else {
 505 
 506                         $dates['m_start']   = 7;
 507                         $dates['m_end']     = 9;
 508                         $dates['year']      = date( 'Y' );
 509 
 510                     }
 511                 break;
 512 
 513                 case 'this_year' :
 514                     $dates['day']       = null;
 515                     $dates['m_start']   = null;
 516                     $dates['m_end']     = null;
 517                     $dates['year']      = date( 'Y' );
 518                 break;
 519 
 520                 case 'last_year' :
 521                     $dates['day']       = null;
 522                     $dates['m_start']   = null;
 523                     $dates['m_end']     = null;
 524                     $dates['year']      = date( 'Y' ) - 1;
 525                 break;
 526 
 527             endswitch;
 528         }
 529 
 530         return apply_filters( 'edd_api_stat_dates', $dates );
 531     }
 532 
 533     /**
 534      * Process Get Customers API Request
 535      *
 536      * @access public
 537      * @since 1.5
 538      * @author Daniel J Griffiths
 539      * @global object $wpdb Used to query the database using the WordPress
 540      *   Database API
 541      * @param int $customer Customer ID
 542      * @return array $customers Multidimensional array of the customers
 543      */
 544     public function get_customers( $customer = null ) {
 545         if ( $customer == null ) {
 546             global $wpdb;
 547 
 548             $paged    = $this->get_paged();
 549             $per_page = $this->per_page();
 550             $offset   = $per_page * ( $paged - 1 );
 551             $customer_list_query = $wpdb->get_col( "SELECT DISTINCT meta_value FROM $wpdb->postmeta where meta_key = '_edd_payment_user_email' ORDER BY meta_id DESC LIMIT $per_page OFFSET $offset" );
 552             $customer_count = 0;
 553 
 554             foreach ( $customer_list_query as $customer_email ) {
 555                 $customer_info = get_user_by( 'email', $customer_email );
 556 
 557                 if ( $customer_info ) {
 558                     // Customer with registered account
 559                     $customers['customers'][$customer_count]['info']['id']           = $customer_info->ID;
 560                     $customers['customers'][$customer_count]['info']['username']     = $customer_info->user_login;
 561                     $customers['customers'][$customer_count]['info']['display_name'] = $customer_info->display_name;
 562                     $customers['customers'][$customer_count]['info']['first_name']   = $customer_info->user_firstname;
 563                     $customers['customers'][$customer_count]['info']['last_name']    = $customer_info->user_lastname;
 564                     $customers['customers'][$customer_count]['info']['email']        = $customer_info->user_email;
 565                 } else {
 566                     // Guest customer
 567                     $customers['customers'][$customer_count]['info']['id']           = -1;
 568                     $customers['customers'][$customer_count]['info']['username']     = __( 'Guest', 'edd' );
 569                     $customers['customers'][$customer_count]['info']['display_name'] = __( 'Guest', 'edd' );
 570                     $customers['customers'][$customer_count]['info']['first_name']   = __( 'Guest', 'edd' );
 571                     $customers['customers'][$customer_count]['info']['last_name']    = __( 'Guest', 'edd' );
 572                     $customers['customers'][$customer_count]['info']['email']        = $customer_email;
 573                 }
 574 
 575                 $customers['customers'][$customer_count]['stats']['total_purchases'] = edd_count_purchases_of_customer( $customer_email );
 576                 $customers['customers'][$customer_count]['stats']['total_spent']     = edd_purchase_total_of_user( $customer_email );
 577                 $customers['customers'][$customer_count]['stats']['total_downloads'] = edd_count_file_downloads_of_user( $customer_email );
 578 
 579                 $customer_count++;
 580             }
 581         } else {
 582             if ( is_numeric( $customer ) ) {
 583                 $customer_info = get_userdata( $customer );
 584             } else {
 585                 $customer_info = get_user_by( 'email', $customer );
 586             }
 587 
 588             if ( $customer_info && edd_has_purchases( $customer_info->ID ) ) {
 589                 $customers['customers'][0]['info']['id']               = $customer_info->ID;
 590                 $customers['customers'][0]['info']['username']         = $customer_info->user_login;
 591                 $customers['customers'][0]['info']['display_name']     = $customer_info->display_name;
 592                 $customers['customers'][0]['info']['first_name']       = $customer_info->user_firstname;
 593                 $customers['customers'][0]['info']['last_name']        = $customer_info->user_lastname;
 594                 $customers['customers'][0]['info']['email']            = $customer_info->user_email;
 595 
 596                 $customers['customers'][0]['stats']['total_purchases'] = edd_count_purchases_of_customer( $customer );
 597                 $customers['customers'][0]['stats']['total_spent']     = edd_purchase_total_of_user( $customer );
 598                 $customers['customers'][0]['stats']['total_downloads'] = edd_count_file_downloads_of_user( $customer );
 599             } else {
 600                 $error['error'] = sprintf( __( 'Customer %s not found!', 'edd' ), $customer );
 601                 return $error;
 602             }
 603         }
 604 
 605         return $customers;
 606     }
 607 
 608     /**
 609      * Process Get Products API Request
 610      *
 611      * @access public
 612      * @author Daniel J Griffiths
 613      * @since 1.5
 614      * @param int $product Product (Download) ID
 615      * @return array $customers Multidimensional array of the products
 616      */
 617     public function get_products( $product = null ) {
 618         $products = array();
 619 
 620         if ( $product == null ) {
 621             $products['products'] = array();
 622 
 623             $product_list = get_posts( array( 'post_type' => 'download', 'posts_per_page' => $this->per_page(), 'paged' => $this->get_paged() ) );
 624 
 625             if ( $product_list ) {
 626                 $i = 0;
 627                 foreach ( $product_list as $product_info ) {
 628                     $products['products'][$i]['info']['id']                           = $product_info->ID;
 629                     $products['products'][$i]['info']['slug']                         = $product_info->post_name;
 630                     $products['products'][$i]['info']['title']                        = $product_info->post_title;
 631                     $products['products'][$i]['info']['create_date']                  = $product_info->post_date;
 632                     $products['products'][$i]['info']['modified_date']                = $product_info->post_modified;
 633                     $products['products'][$i]['info']['status']                       = $product_info->post_status;
 634                     $products['products'][$i]['info']['link']                         = html_entity_decode( $product_info->guid );
 635                     $products['products'][$i]['info']['content']                      = $product_info->post_content;
 636                     $products['products'][$i]['info']['thumbnail']                    = wp_get_attachment_url( get_post_thumbnail_id( $product_info->ID ) );
 637 
 638                     $products['products'][$i]['stats']['total']['sales']              = edd_get_download_sales_stats( $product_info->ID );
 639                     $products['products'][$i]['stats']['total']['earnings']           = edd_get_download_earnings_stats( $product_info->ID );
 640                     $products['products'][$i]['stats']['monthly_average']['sales']    = edd_get_average_monthly_download_sales( $product_info->ID );
 641                     $products['products'][$i]['stats']['monthly_average']['earnings'] = edd_get_average_monthly_download_earnings( $product_info->ID );
 642 
 643                     if ( edd_has_variable_prices( $product_info->ID ) ) {
 644                         foreach ( edd_get_variable_prices( $product_info->ID ) as $price ) {
 645                             $products['products'][$i]['pricing'][ sanitize_key( $price['name'] ) ] = $price['amount'];
 646                         }
 647                     } else {
 648                         $products['products'][$i]['pricing']['amount'] = edd_get_download_price( $product_info->ID );
 649                     }
 650 
 651                     foreach ( edd_get_download_files( $product_info->ID ) as $file ) {
 652                         $products['products'][$i]['files'][] = $file;
 653                     }
 654 
 655                     $products['products'][$i]['notes'] = edd_get_product_notes( $product_info->ID );
 656                     $i++;
 657                 }
 658             }
 659         } else {
 660             if ( get_post_type( $product ) == 'download' ) {
 661                 $product_info = get_post( $product );
 662 
 663                 $products['products'][0]['info']['id']                           = $product_info->ID;
 664                 $products['products'][0]['info']['slug']                         = $product_info->post_name;
 665                 $products['products'][0]['info']['title']                        = $product_info->post_title;
 666                 $products['products'][0]['info']['create_date']                  = $product_info->post_date;
 667                 $products['products'][0]['info']['modified_date']                = $product_info->post_modified;
 668                 $products['products'][0]['info']['status']                       = $product_info->post_status;
 669                 $products['products'][0]['info']['link']                         = html_entity_decode( $product_info->guid );
 670                 $products['products'][0]['info']['content']                      = $product_info->post_content;
 671                 $products['products'][0]['info']['thumbnail']                    = wp_get_attachment_url( get_post_thumbnail_id( $product_info->ID ) );
 672 
 673                 $products['products'][0]['stats']['total']['sales']              = edd_get_download_sales_stats( $product_info->ID );
 674                 $products['products'][0]['stats']['total']['earnings']           = edd_get_download_earnings_stats( $product_info->ID );
 675                 $products['products'][0]['stats']['monthly_average']['sales']    = edd_get_average_monthly_download_sales( $product_info->ID );
 676                 $products['products'][0]['stats']['monthly_average']['earnings'] = edd_get_average_monthly_download_earnings( $product_info->ID );
 677 
 678                 if ( edd_has_variable_prices( $product_info->ID ) ) {
 679                     foreach ( edd_get_variable_prices( $product_info->ID ) as $price ) {
 680                         $products['products'][0]['pricing'][ sanitize_key( $price['name'] ) ] = $price['amount'];
 681                     }
 682                 } else {
 683                     $products['products'][0]['pricing']['amount'] = edd_get_download_price( $product_info->ID );
 684                 }
 685 
 686                 foreach ( edd_get_download_files( $product_info->ID ) as $file ) {
 687                     $products['products'][0]['files'][] = $file;
 688                 }
 689 
 690                 $products['products'][0]['notes'] = edd_get_product_notes( $product_info->ID );
 691             } else {
 692                 $error['error'] = sprintf( __( 'Product %s not found!', 'edd' ), $product );
 693                 return $error;
 694             }
 695         }
 696 
 697         return $products;
 698     }
 699 
 700     /**
 701      * Process Get Stats API Request
 702      *
 703      * @access public
 704      * @author Daniel J Griffiths
 705      * @since 1.5
 706      * @global object $wpdb Used to query the database using the WordPress
 707      *   Database API
 708      * @param array $args Arguments provided by API Request
 709      */
 710     public function get_stats( $args = array() ) {
 711         $defaults = array(
 712             'type'      => '',
 713             'product'   => null,
 714             'date'      => null,
 715             'startdate' => null,
 716             'enddate'   => null
 717         );
 718 
 719         $args = wp_parse_args( $args, $defaults );
 720 
 721         $dates = $this->get_dates( $args );
 722 
 723         if ( $args['type'] == 'sales' ) {
 724             if ( $args['product'] == null ) {
 725                 if ( $args['date'] == null ) {
 726                     // Default sales return
 727                     $previous_month = date( 'n' ) == 1 ? 12 : date( 'n' ) - 1;
 728                     $previous_year  = date( 'n' ) == 1 ? date( 'Y' ) - 1 : date( 'Y' );
 729 
 730                     $sales['sales']['current_month'] = edd_get_sales_by_date( null, date( 'n' ), date( 'Y' ) );
 731                     $sales['sales']['last_month']    = edd_get_sales_by_date( null, $previous_month, $previous_year );
 732                     $sales['sales']['totals']        = edd_get_total_sales();
 733                 } elseif( $args['date'] === 'range' ) {
 734                     // Return sales for a date range
 735 
 736                     // Ensure the end date is later than the start date
 737                     if( $args['enddate'] < $args['startdate'] ) {
 738                         $error['error'] = __( 'The end date must be later than the start date!', 'edd' );
 739                     }
 740 
 741                     // Ensure both the start and end date are specified
 742                     if ( empty( $args['startdate'] ) || empty( $args['enddate'] ) ) {
 743                         $error['error'] = __( 'Invalid or no date range specified!', 'edd' );
 744                     }
 745 
 746                     $total = 0;
 747 
 748                     // Loop through the years
 749                     $year = $dates['year'];
 750                     while( $year <= $dates['year_end' ] ) :
 751                         // Loop through the months
 752                         $month = $dates['m_start'];
 753 
 754                         while( $month <= $dates['m_end'] ) :
 755                             // Loop through the days
 756                             $day           = $month > $dates['m_start'] ? 1 : $dates['day_start'];
 757                             $days_in_month = cal_days_in_month( CAL_GREGORIAN, $month, $year );
 758 
 759                             while( $day <= $days_in_month ) :
 760                                 $sale_count = edd_get_sales_by_date( $day, $month, $year );
 761                                 $sales['sales'][ date( 'Ymd', strtotime( $year . '/' . $month . '/' . $day ) ) ] = $sale_count;
 762                                 $total += $sale_count;
 763 
 764                                 $day++;
 765                             endwhile;
 766 
 767                             $month++;
 768                         endwhile;
 769 
 770                         $year++;
 771                     endwhile;
 772 
 773                     $sales['totals'] = $total;
 774                 } else {
 775                     if( $args['date'] == 'this_quarter' || $args['date'] == 'last_quarter'  ) {
 776                         $sales_count = 0;
 777 
 778                         // Loop through the months
 779                         $month = $dates['m_start'];
 780 
 781                         while( $month <= $dates['m_end'] ) :
 782                             $sales_count += edd_get_sales_by_date( null, $month, $dates['year'] );
 783                             $month++;
 784                         endwhile;
 785 
 786                         $sales['sales'][ $args['date'] ] = $sales_count;
 787                     } else {
 788                         $sales['sales'][ $args['date'] ] = edd_get_sales_by_date( $dates['day'], $dates['m_start'], $dates['year'] );
 789                     }
 790                 }
 791             } elseif ( $args['product'] == 'all' ) {
 792                 $products = get_posts( array( 'post_type' => 'download', 'nopaging' => true ) );
 793                 $i = 0;
 794                 foreach ( $products as $product_info ) {
 795                     $sales['sales'][$i] = array( $product_info->post_name => edd_get_download_sales_stats( $product_info->ID ) );
 796                     $i++;
 797                 }
 798             } else {
 799                 if ( get_post_type( $args['product'] ) == 'download' ) {
 800                     $product_info = get_post( $args['product'] );
 801                     $sales['sales'][0] = array( $product_info->post_name => edd_get_download_sales_stats( $args['product'] ) );
 802                 } else {
 803                     $error['error'] = sprintf( __( 'Product %s not found!', 'edd' ), $args['product'] );
 804                 }
 805             }
 806 
 807             if ( ! empty( $error ) )
 808                 return $error;
 809 
 810             return $sales;
 811         } elseif ( $args['type'] == 'earnings' ) {
 812             if ( $args['product'] == null ) {
 813                 if ( $args['date'] == null ) {
 814                     // Default earnings return
 815                     $previous_month = date( 'n' ) == 1 ? 12 : date( 'n' ) - 1;
 816                     $previous_year  = date( 'n' ) == 1 ? date( 'Y' ) - 1 : date( 'Y' );
 817 
 818                     $earnings['earnings']['current_month'] = edd_get_earnings_by_date( null, date( 'n' ), date( 'Y' ) );
 819                     $earnings['earnings']['last_month'] = edd_get_earnings_by_date( null, $previous_month, $previous_year );
 820                     $earnings['earnings']['totals'] = edd_get_total_earnings();
 821                 } elseif ( $args['date'] === 'range' ) {
 822                     // Return sales for a date range
 823 
 824                     // Ensure the end date is later than the start date
 825                     if ( $args['enddate'] < $args['startdate'] ) {
 826                         $error['error'] = __( 'The end date must be later than the start date!', 'edd' );
 827                     }
 828 
 829                     // Ensure both the start and end date are specified
 830                     if ( empty( $args['startdate'] ) || empty( $args['enddate'] ) ) {
 831                         $error['error'] = __( 'Invalid or no date range specified!', 'edd' );
 832                     }
 833 
 834                     $total = (float) 0.00;
 835 
 836                     // Loop through the years
 837                     $year = $dates['year'];
 838                     while ( $year <= $dates['year_end' ] ) :
 839                         // Loop through the months
 840                         $month = $dates['m_start'];
 841 
 842                         while( $month <= $dates['m_end'] ) :
 843                             // Loop through the days
 844                             $day           = $month > $dates['m_start'] ? 1 : $dates['day_start'];
 845                             $days_in_month = cal_days_in_month( CAL_GREGORIAN, $month, $year );
 846 
 847                             while( $day <= $days_in_month ) :
 848                                 $sale_count = edd_get_earnings_by_date( $day, $month, $year );
 849                                 $earnings['earnings'][ date( 'Ymd', strtotime( $year . '/' . $month . '/' . $day ) ) ] = $sale_count;
 850                                 $total += $sale_count;
 851 
 852                                 $day++;
 853                             endwhile;
 854 
 855                             $month++;
 856                         endwhile;
 857 
 858                         $year++;
 859                     endwhile;
 860 
 861                     $earnings['totals'] = $total;
 862                 } else {
 863                     if ( $args['date'] == 'this_quarter' || $args['date'] == 'last_quarter'  ) {
 864                         $earnings_count = (float) 0.00;
 865 
 866                         // Loop through the months
 867                         $month = $dates['m_start'];
 868 
 869                         while ( $month <= $dates['m_end'] ) :
 870                             $earnings_count += edd_get_earnings_by_date( null, $month, $dates['year'] );
 871                             $month++;
 872                         endwhile;
 873 
 874                         $earnings['earnings'][ $args['date'] ] = $earnings_count;
 875                     } else {
 876                         $earnings['earnings'][ $args['date'] ] = edd_get_earnings_by_date( $dates['day'], $dates['m_start'], $dates['year'] );
 877                     }
 878                 }
 879             } elseif ( $args['product'] == 'all' ) {
 880                 $products = get_posts( array( 'post_type' => 'download', 'nopaging' => true ) );
 881 
 882                 $i = 0;
 883                 foreach ( $products as $product_info ) {
 884                     $earnings['earnings'][ $i ] = array( $product_info->post_name => edd_get_download_earnings_stats( $product_info->ID ) );
 885                     $i++;
 886                 }
 887             } else {
 888                 if ( get_post_type( $args['product'] ) == 'download' ) {
 889                     $product_info = get_post( $args['product'] );
 890                     $earnings['earnings'][0] = array( $product_info->post_name => edd_get_download_earnings_stats( $args['product'] ) );
 891                 } else {
 892                     $error['error'] = sprintf( __( 'Product %s not found!', 'edd' ), $args['product'] );
 893                 }
 894             }
 895 
 896             if ( ! empty( $error ) )
 897                 return $error;
 898 
 899             return $earnings;
 900         } elseif ( $args['type'] == 'customers' ) {
 901             global $wpdb;
 902 
 903             $stats = array();
 904 
 905             $count = $wpdb->get_col( "SELECT COUNT(DISTINCT meta_value) FROM $wpdb->postmeta WHERE meta_key = '_edd_payment_user_email'" );
 906 
 907             $stats['customers']['total_customers'] = $count[0];
 908 
 909             return $stats;
 910         }
 911     }
 912 
 913     /**
 914      * Retrieves Recent Sales
 915      *
 916      * @access public
 917      * @since  1.5
 918      * @return array
 919      */
 920     public function get_recent_sales() {
 921         $sales = array();
 922 
 923         $query = edd_get_payments( array( 'number' => $this->per_page(), 'page' => $this->get_paged() ) );
 924 
 925         if ( $query ) {
 926             $i = 0;
 927             foreach ( $query as $payment ) {
 928                 $payment_meta          = edd_get_payment_meta( $payment->ID );
 929                 $user_info             = edd_get_payment_meta_user_info( $payment->ID );
 930                 $cart_items            = edd_get_payment_meta_cart_details( $payment->ID );
 931 
 932                 $sales['sales'][ $i ]['ID']       = $payment->ID;
 933                 $sales['sales'][ $i ]['key']      = edd_get_payment_key( $payment->ID );
 934                 $sales['sales'][ $i ]['subtotal'] = edd_get_payment_subtotal( $payment->ID );
 935                 $sales['sales'][ $i ]['tax']      = edd_get_payment_tax( $payment->ID );
 936                 $sales['sales'][ $i ]['fees']     = edd_get_payment_fees( $payment->ID );
 937                 $sales['sales'][ $i ]['total']    = edd_get_payment_amount( $payment->ID );
 938                 $sales['sales'][ $i ]['gateway']  = edd_get_payment_gateway( $payment->ID );
 939                 $sales['sales'][ $i ]['email']    = edd_get_payment_user_email( $payment->ID );
 940                 $sales['sales'][ $i ]['date']     = $payment->post_date;
 941                 $sales['sales'][ $i ]['products'] = array();
 942 
 943                 $c = 0;
 944 
 945                 foreach ( $cart_items as $key => $item ) {
 946                     $price_override = isset( $payment_meta['cart_details'] ) ? $item['price'] : null;
 947                     $price          = edd_get_download_final_price( $item['id'], $user_info, $price_override );
 948 
 949                     if ( isset( $cart_items[ $key ]['item_number'] ) ) {
 950                         $price_name     = '';
 951                         $price_options  = $cart_items[ $key ]['item_number']['options'];
 952                         if ( isset( $price_options['price_id'] ) ) {
 953                             $price_name = edd_get_price_option_name( $item['id'], $price_options['price_id'], $payment->ID );
 954                         }
 955                     }
 956 
 957                     $sales['sales'][ $i ]['products'][ $c ]['name']       = get_the_title( $item['id'] );
 958                     $sales['sales'][ $i ]['products'][ $c ]['price']      = $price;
 959                     $sales['sales'][ $i ]['products'][ $c ]['price_name'] = $price_name;
 960                     $c++;
 961                 }
 962 
 963                 $i++;
 964             }
 965         }
 966         return $sales;
 967     }
 968 
 969     /**
 970      * Log each API request, if enabled
 971      *
 972      * @access private
 973      * @since  1.5
 974      * @global $edd_logs
 975      * @global $wp_query
 976      * @param array $data
 977      * @return void
 978      */
 979     private function log_request( $data = array() ) {
 980         if ( ! $this->log_requests )
 981             return;
 982 
 983         global $edd_logs, $wp_query;
 984 
 985         $query = array(
 986             'key'       => $wp_query->query_vars['key'],
 987             'query'     => isset( $wp_query->query_vars['query'] )     ? $wp_query->query_vars['query']     : null,
 988             'type'      => isset( $wp_query->query_vars['type'] )      ? $wp_query->query_vars['type']      : null,
 989             'product'   => isset( $wp_query->query_vars['product'] )   ? $wp_query->query_vars['product']   : null,
 990             'customer'  => isset( $wp_query->query_vars['customer'] )  ? $wp_query->query_vars['customer']  : null,
 991             'date'      => isset( $wp_query->query_vars['date'] )      ? $wp_query->query_vars['date']      : null,
 992             'startdate' => isset( $wp_query->query_vars['startdate'] ) ? $wp_query->query_vars['startdate'] : null,
 993             'enddate'   => isset( $wp_query->query_vars['enddate'] )   ? $wp_query->query_vars['enddate']   : null,
 994         );
 995 
 996         $log_data = array(
 997             'log_type'     => 'api_request',
 998             'post_excerpt' => http_build_query( $query ),
 999             'post_content' => ! empty( $data['error'] ) ? $data['error'] : '',
1000         );
1001 
1002         $log_meta = array(
1003             'request_ip' => edd_get_ip(),
1004             'user'       => $this->user_id,
1005             'key'        => $wp_query->query_vars['key']
1006         );
1007 
1008         $edd_logs->insert_log( $log_data, $log_meta );
1009     }
1010 
1011     /**
1012      * Output Query in either JSON/XML. The query data is outputted as JSON
1013      * by default
1014      *
1015      * @access public
1016      * @author Daniel J Griffiths
1017      * @since 1.5
1018      * @global $wp_query
1019      * @param array $data
1020      * @return void
1021      */
1022     public function output( $data ) {
1023         global $wp_query;
1024 
1025         $format = $this->get_output_format();
1026 
1027         do_action( 'edd_api_output_before', $data, $this, $format );
1028 
1029         switch( $format ) :
1030 
1031             case 'xml' :
1032 
1033                 require_once EDD_PLUGIN_DIR . 'includes/libraries/array2xml.php';
1034                 $xml = Array2XML::createXML( 'edd', $data );
1035                 echo $xml->saveXML();
1036 
1037                 break;
1038 
1039             case 'json' :
1040 
1041                 header( 'Content-Type: application/json' );
1042                 if ( ! empty( $this->pretty_print ) )
1043                     echo json_encode( $data, $this->pretty_print );
1044                 else
1045                     echo json_encode( $data );
1046 
1047                 break;
1048 
1049 
1050             default :
1051 
1052                 // Allow other formats to be added via extensions
1053                 do_action( 'edd_api_output_' . $format, $data, $this );
1054 
1055                 break;
1056 
1057         endswitch;
1058 
1059         do_action( 'edd_api_output_after', $data, $this, $format );
1060 
1061         exit;
1062     }
1063 
1064     /**
1065      * Modify User Profile
1066      *
1067      * Modifies the output of profile.php to add key generation/revocation
1068      *
1069      * @access public
1070      * @author Daniel J Griffiths
1071      * @since 1.5
1072      * @global $edd_options Array of all the EDD Options
1073      * @param object $user Current user info
1074      * @return void
1075      */
1076     function user_key_field( $user ) {
1077         global $edd_options;
1078 
1079         if ( ( isset( $edd_options['api_allow_user_keys'] ) || current_user_can( 'manage_shop_settings' ) ) && current_user_can( 'view_shop_reports' ) ) {
1080             $user = get_userdata( $user->ID );
1081             ?>
1082             <table class="form-table">
1083                 <tbody>
1084                     <tr>
1085                         <th>
1086                             <label for="edd_set_api_key"><?php _e( 'Easy Digital Downloads API Keys', 'edd' ); ?></label>
1087                         </th>
1088                         <td>
1089                             <?php if ( empty( $user->edd_user_public_key ) ) { ?>
1090                             <input name="edd_set_api_key" type="checkbox" id="edd_set_api_key" value="0" />
1091                             <span class="description"><?php _e( 'Generate API Key', 'edd' ); ?></span>
1092                             <?php } else { ?>
1093                                 <strong><?php _e( 'Public key:' ); ?>&nbsp;</strong><span id="publickey"><?php echo $user->edd_user_public_key; ?></span><br/>
1094                                 <strong><?php _e( 'Secret key:' ); ?>&nbsp;</strong><span id="privatekey"><?php echo $user->edd_user_secret_key; ?></span><br/>
1095                                 <strong><?php _e( 'Token:' ); ?>&nbsp;</strong><span id="token"><?php echo hash( 'md5', $user->edd_user_secret_key . $user->edd_user_public_key ); ?></span><br/>
1096                                 <input name="edd_set_api_key" type="checkbox" id="edd_set_api_key" value="0" />
1097                                 <span class="description"><?php _e( 'Revoke API Keys', 'edd' ); ?></span>
1098                             <?php } ?>
1099                         </td>
1100                     </tr>
1101                 </tbody>
1102             </table>
1103         <?php }
1104     }
1105 
1106     /**
1107      * Generate and Save API key
1108      *
1109      * Generates the key requested by user_key_field and stores it in the database
1110      *
1111      * @access public
1112      * @author Daniel J Griffiths
1113      * @since 1.5
1114      * @param int $user_id
1115      * @return void
1116      */
1117     public function update_key( $user_id ) {
1118         if ( current_user_can( 'edit_user', $user_id ) && isset( $_POST['edd_set_api_key'] ) ) {
1119             $user = get_userdata( $user_id );
1120 
1121             if ( empty( $user->edd_user_public_key ) ) {
1122                 $public = hash( 'md5', $user->user_email . date( 'U' ) );
1123                 update_user_meta( $user_id, 'edd_user_public_key', $public );
1124             } else {
1125                 delete_user_meta( $user_id, 'edd_user_public_key' );
1126             }
1127 
1128             if ( empty( $user->edd_user_secret_key ) ) {
1129                 $secret = hash( 'md5', $user->ID . date( 'U' ) );
1130                 update_user_meta( $user_id, 'edd_user_secret_key', $secret );
1131             } else {
1132                 delete_user_meta( $user_id, 'edd_user_secret_key' );
1133             }
1134         }
1135     }
1136 }
Easy Digital Downloads API documentation generated by ApiGen 2.8.0