array( array( &$this, 'AP_editFeed' ), __( 'Edit feed', 'LDB_AP' ) ), 'affiliate_press_view' => array( array( &$this, 'AP_viewFeed' ), __( 'View feed', 'LDB_AP' ) ), 'affiliate_press_linktoproduct' => array( array( &$this, 'AP_linkToProduct' ), __( 'Link item to an existing product', 'LDB_AP' ) ) ); $this->AP_registerHiddenPages( $hiddenpages, $parent ); } /* Function to register the hidden pages */ function AP_registerHiddenPages( $pages, $parent ) { global $_registered_pages; foreach( $pages as $slug => $function ) { $hookname = get_plugin_page_hookname( $slug, $parent ); $this->titles[ $slug ] = $function[1]; if ( !empty( $hookname ) ) { add_action( $hookname, $function[0] ); } $_registered_pages[ $hookname ] = true; add_action( 'admin_print_styles-' . $hookname, array( &$this, 'AP_loadStyle' ) ); } if( isset( $_GET['page'] ) && isset( $pages[ $_GET['page'] ] ) && isset( $pages[ $_GET['page'] ][1] ) ) add_filter( 'admin_title', array( &$this, 'AP_changeTitle' ), 10, 2 ); } function AP_changeTitle( $admin_title, $title ) { if( isset( $_GET['page'] ) && isset( $this->titles[ $_GET['page'] ] ) ) return $this->titles[ $_GET['page'] ] . $admin_title; } /* Function to load the stylesheet and some scripts. */ function AP_loadStyle() { wp_enqueue_style( 'APstyle', LDB_AP_URL . 'styles.css' ); wp_enqueue_script( 'ap_message', LDB_AP_SCRIPTS_URL . 'message.js' ); wp_enqueue_script( 'postbox' ); wp_enqueue_script( 'dashboard' ); } /* Function to load the custom post type. */ function AP_loadCpt() { $labels = array( 'name' => __( 'Products', 'LDB_AP' ), 'singular_name' => __( 'Product', 'LDB_AP' ), 'add_new' => __( 'Add New', 'LDB_AP' ), 'add_new_item' => __( 'Add New Product', 'LDB_AP' ), 'edit_item' => __( 'Edit Product', 'LDB_AP' ), 'new_item' => __( 'New Product', 'LDB_AP' ), 'all_items' => __( 'All Products', 'LDB_AP' ), 'view_item' => __( 'View Product', 'LDB_AP' ), 'search_items' => __( 'Search Products', 'LDB_AP' ), 'not_found' => __( 'No products found', 'LDB_AP' ), 'not_found_in_trash' => __( 'No products found in Trash', 'LDB_AP' ), 'parent_item_colon' => '', 'menu_name' => __( 'Products', 'LDB_AP' ) ); $args = array( 'labels' => $labels, 'public' => true, 'publicly_queryable' => true, 'show_ui' => true, 'show_in_menu' => true, 'query_var' => true, 'rewrite' => true, 'capability_type' => 'post', 'has_archive' => true, 'hierarchical' => false, 'menu_position' => null, 'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'comments', 'custom-fields' ) ); register_post_type( 'product', $args ); add_filter( 'manage_product_posts_columns', array( &$this, 'AP_changeColumns' ) ); add_filter( 'manage_product_posts_custom_column', array( &$this, 'AP_addColumnContent' ) ); add_filter( 'manage_edit-product_sortable_columns', array( &$this, 'AP_sortableColumns' ) ); } /* Function that adds additional columns on the products index page. */ function AP_changeColumns( $cols ) { $newcols = array(); foreach( $cols as $key => $value ) { $newcols[ $key ] = $value; if( $key === 'title' ) $newcols['prices'] = __( 'Number of prices', 'LDB_AP' ); } return $newcols; } /* Function that adds content to the additional columns on the products index page. */ function AP_addColumnContent( $column_name ) { global $post, $wpdb; switch ( $column_name ) { case 'prices' : $results = $wpdb->get_results( 'SELECT apfeeds.title, apfeeds.currency, apprices.price FROM ' . $wpdb->prefix . 'apprices apprices, ' . $wpdb->prefix . 'apfeeds apfeeds WHERE apprices.productID = ' . $post->ID . ' AND apprices.feedID = apfeeds.ID AND apprices.online = 1 ORDER BY apprices.price ASC' ); echo count( $results ); break; } } function AP_sortableColumns() { return array( 'prices' => 'prices', 'title' => 'title', 'author' => 'author', 'date' => 'date', ); } /* Function that fetches the current action, partly stolen from core. */ function AP_currentAction() { $action = false; if ( isset( $_REQUEST['action'] ) && -1 != $_REQUEST['action'] ) $action = $_REQUEST['action']; if ( isset( $_REQUEST['action2'] ) && -1 != $_REQUEST['action2'] ) $action = $_REQUEST['action2']; if ( !$action && isset( $_GET['action'] ) ) $action = $_GET['action']; return $action; } /* Function to perform the actions issues by forms. */ function AP_performAction() { global $wpdb; $action = $this->AP_currentAction(); switch( $action ) { case 'process': if( isset( $_GET['feed'] ) && is_array( $_GET['feed'] ) && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'bulk-feeds' ) ) { foreach( $_GET['feed'] as $feed ) { $this->AP_processPrices( $feed ); } $this->AP_setMessage( __( 'The feeds were processed succesfully.', 'LDB_AP' ), 'success' ); } else if( isset( $_GET['feed'] ) && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'process' . $_GET['feed'] ) ) { $this->AP_processPrices( $_GET['feed'] ); $this->AP_setMessage( __( 'The feed was processed succesfully.', 'LDB_AP' ), 'success' ); } else { wp_die( __( "You're not allowed to perform the requested action." ) ); } break; case 'delete': if( isset( $_GET['feed'] ) && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'bulk-feeds' ) ) { $wpdb->query( 'DELETE FROM ' . $wpdb->prefix . 'apfeeds WHERE ID IN (' . implode( ', ', $_GET['feed'] ) . ')' ); $this->AP_setMessage( __( 'The feeds were succesfully deleted.', 'LDB_AP' ), 'success' ); } if( isset( $_REQUEST['feed'] ) && isset( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( $_REQUEST['_wpnonce'], 'delete' . $_REQUEST['feed'] ) ) { $wpdb->query( 'DELETE FROM ' . $wpdb->prefix . 'apfeeds WHERE id=' . $_GET['feed'] ); $this->AP_setMessage( __( 'The feed was succesfully deleted.', 'LDB_AP' ), 'success' ); } break; case 'draft': if( isset( $_GET['identifier'] ) && isset( $_GET['feed'] ) && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'bulk-feeds' ) ) { $items = @$this->AP_processFeed( $_GET['feed'] ); foreach( $_GET['identifier'] as $identifier ) { foreach( $items as $item ) { if( $item['identifier'] === $identifier ) if( $this->AP_createDraft( $item['name'], $item['matches'], $item['identifier'], $item['image'] ) ) $this->AP_setMessage( sprintf( __( 'The draft for %s was created succesfully.', 'LDB_AP' ), $item['name'] ), 'success' ); } } $feed = @$this->AP_getFeed( $_GET['feed'] ); $this->AP_processPrices( $_GET['feed'] ); $this->action = 'view'; } else if( isset( $_GET['identifier'] ) && isset( $_GET['feed'] ) && isset( $_GET['_draftnonce'] ) && wp_verify_nonce( $_GET['_draftnonce'], 'draft' . $_GET['identifier'] ) ) { $items = @$this->AP_processFeed( $_GET['feed'] ); $post = ''; $postID = false; $message = ''; $messagetype= ''; foreach( $items as $item ) { if( $item['identifier'] === $_GET['identifier'] ) $postID = $this->AP_createDraft( $item['name'], $item['matches'], $item['identifier'], $item['image'] ); } if( $postID && !is_array( $postID ) ) $post = '&post=' . $postID; $feed = @$this->AP_getFeed( $_GET['feed'] ); $this->AP_processPrices( $_GET['feed'] ); $paged = ''; $orderby = ''; $order = ''; if( isset( $_GET['paged'] ) ) $paged = '&paged=' . $_GET['paged']; if( isset( $_GET['orderby'] ) ) $orderby = '&orderby=' . $_GET['orderby']; if( isset( $_GET['order'] ) ) $order = '&order=' . $_GET['order']; header( 'Location:?page=' . $_GET['page'] . '&action=view&feed=' . $_GET['feed'] . '&_viewnonce=' . $_GET['_viewnonce'] . $paged . $orderby . $order . $post ); } break; default: if( isset( $_POST['wp_nonce_add'] ) && wp_verify_nonce( $_POST['wp_nonce_add'], 'addfeed' ) ) { $data = $this->AP_prepareFeedData(); $wpdb->insert( $wpdb->prefix . 'apfeeds', $data ); $this->AP_setMessage( __( 'The feed was succesfully saved.', 'LDB_AP' ), 'success' ); } else if( isset( $_POST['wp_nonce_edit'] ) && wp_verify_nonce( $_POST['wp_nonce_edit'], 'editfeed' ) ) { $data = $this->AP_prepareFeedData(); $wpdb->update( $wpdb->prefix . 'apfeeds', $data, array( 'ID' => $_POST['ID'] ) ); $this->AP_setMessage( __( 'The feed was succesfully updated.', 'LDB_AP' ), 'success' ); } else if( isset( $_POST['wp_nonce_linkto'] ) && isset( $_POST['identifier'] ) && wp_verify_nonce( $_POST['wp_nonce_linkto'], 'linkto' . $_POST['identifier'] ) ) { add_post_meta( $_POST['product'], $_POST['matches'], $_POST['identifier'] ); header( 'Location:' . $_POST['view_referer'] . '&linkto=' . $_POST['product'] ); } break; } } /* Function that adds the custom meta box for the products. */ function AP_addCustomMetaBox() { add_meta_box( 'affiliate-press', __( 'Prices from feeds', 'LDB_AP' ), array( &$this, 'AP_pricesBox' ), 'product', 'side', 'default' ); } /* Function that fetches and show the content for the meta box on the edit product page. */ function AP_pricesBox() { global $post, $wpdb; $productID = $post->ID; $results = $wpdb->get_results( 'SELECT apfeeds.title, apfeeds.currency, apprices.price FROM ' . $wpdb->prefix . 'apprices apprices, ' . $wpdb->prefix . 'apfeeds apfeeds WHERE apprices.productID = ' . $productID . ' AND apprices.feedID = apfeeds.ID AND apprices.online = 1 ORDER BY apprices.price ASC' ); $pricetable = ''; if( $results ) { $r = 1; foreach( $results as $result ){ $class = 'normal'; if( count( $results ) === 1 ) { $class = ''; } else if( $r === 1 ) { $class = 'first'; } else if( $r === count( $results ) ) { $class = 'last'; } $pricetable.= ''; $r++; } } else { $pricetable.= ''; } $pricetable.= '
' . $result->title . '' . $result->currency . ' ' . $result->price . '
' . __( 'No prices were found.', 'LDB_AP' ) . '
'; echo $pricetable; } /* Function that shows the dashboard. */ function AP_dashboard() { include( LDB_AP_VIEW_PATH . 'dashboard.php' ); } /* Function that shows the feed index page. */ function AP_feeds() { include( LDB_AP_VIEW_PATH . 'feed-index.php' ); } /* Function that shows the add feed page. */ function AP_addFeed() { $matches = $this->AP_buildSelect( 'matches', $this->AP_getCustomFields() ); include( LDB_AP_VIEW_PATH . 'feed-add.php' ); } /* Function that shows the edit feed page. */ function AP_editFeed() { wp_enqueue_script( 'ap_expand', LDB_AP_SCRIPTS_URL . 'expand.js' ); wp_enqueue_script( 'ap_message', LDB_AP_SCRIPTS_URL . 'message.js' ); if( isset( $_GET['feed'] ) && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'edit' . $_GET['feed'] ) ) { $feed = @$this->AP_getFeed( $_REQUEST['feed'] ); $customfields = $this->AP_getCustomFields(); $matches = $this->AP_buildSelect( 'matches', $this->AP_getCustomFields(), $feed['matches'] ); include( LDB_AP_VIEW_PATH . 'feed-edit.php' ); } else { wp_die( __( "You're not allowed to perform the requested action." ) ); } } /* Function that shows the view feed page. */ function AP_viewFeed() { wp_enqueue_script( 'ap_expand', LDB_AP_SCRIPTS_URL . 'expand.js' ); wp_enqueue_script( 'ap_message', LDB_AP_SCRIPTS_URL . 'message.js' ); if( isset( $_GET['post'] ) ) { $postinfo = get_post( $_GET['post'] ); $this->AP_setMessage( sprintf( __( 'The draft for %s was created succesfully.', 'LDB_AP' ), $postinfo->post_title ), 'success' ); } else if( isset( $_GET['linkto'] ) ) { $postinfo = get_post( $_GET['linkto'] ); $this->AP_setMessage( sprintf( __( 'The item was succesfully linked to the product with title "%s".', 'LDB_AP' ), $postinfo->post_title ), 'success' ); } if( isset( $_GET['feed'] ) && isset( $_GET['_viewnonce'] ) && wp_verify_nonce( $_GET['_viewnonce'], 'view' . $_GET['feed'] ) ) { $feed = @$this->AP_getFeed( $_GET['feed'] ); $items = @$this->AP_processFeed( $_GET['feed'] ); include( LDB_AP_VIEW_PATH . 'feed-view.php' ); } else { wp_die( __( "You're not allowed to perform the requested action." ) ); } } /* Function that adds the item data to an existing product. */ function AP_linkToProduct() { wp_enqueue_script( 'ap_expand', LDB_AP_SCRIPTS_URL . 'expand.js' ); wp_enqueue_script( 'ap_message', LDB_AP_SCRIPTS_URL . 'message.js' ); if( isset( $_GET['identifier'] ) && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'linkto' . $_GET['identifier'] ) ) { $products = array(); $setproducts = array(); $productsarray = array(); $allproducts = get_posts( array( 'post_type' => 'product', 'post_status' => array( 'publish', 'draft' ) ) ); foreach( $allproducts as $product ) { if( !$meta = get_post_meta( $product->ID, $_GET['matches'] ) ) { $products[ $product->ID ] = $product->post_title; } else { if( !in_array( $_GET['identifier'], $meta ) ) { $setproducts[ $product->ID ] = $product->post_title; } } } if( count( $products ) > 0 ) $productsarray[ sprintf( __('Products without %s set', 'LDB_AP' ), $_GET['matches'] ) ] = $products; if( count( $setproducts ) > 0 ) $productsarray[ sprintf( __('Products with %s already set', 'LDB_AP' ), $_GET['matches'] ) ] = $setproducts; $view_referer = $_SERVER['HTTP_REFERER']; $linkto = $this->AP_buildSelect( 'product', $productsarray, false, true ); include( LDB_AP_VIEW_PATH . 'feed-linkto.php' ); } else { wp_die( __( "You're not allowed to perform the requested action." ) ); } } /* Function to show a postbox. */ function AP_postbox( $id, $title, $content ) { $postbox = '

' . $title . '

' . $content . '
'; echo $postbox; } /* Function that shows the sidebar. */ function AP_sidebar() { include( LDB_AP_VIEW_PATH . 'sidebar.php' ); } /* Function that catches the attachment id and assigns it as the feature image to it's parent. */ function AP_catchAttachment( $att_id ){ $post = get_post( $att_id ); update_post_meta( $post->post_parent, '_thumbnail_id' , $att_id ); } /* Function that creates a product draft based on the feed item data. */ function AP_createDraft( $name, $matches, $identifier, $image ) { $data = array( 'post_title' => $name, 'post_type' => 'product' ); $post = wp_insert_post( $data ); add_post_meta( $post, $matches, $identifier ); if( $image && !empty( $image ) ) { add_action( 'add_attachment', array( &$this, 'AP_catchAttachment' ) ); $html = media_sideload_image( $image, $post ); remove_action( 'add_attachment', array( &$this, 'AP_catchAttachment' ) ); } return $post; } /* Function that creates a product draft based on the feed item data. */ function AP_prepareFeedData() { $fields = array( 'title', 'currency', 'url', 'item_xpath', 'name_xpath', 'image_xpath', 'price_xpath', 'link_xpath', 'identifier_xpath', 'matches' ); $data = array(); foreach( $fields as $key => $value ) { if( isset( $_POST[ $value ] ) ) { $data[ $value ] = $_POST[ $value ]; } else { $data[ $value ] = ''; } } if( isset( $_POST['new_matches'] ) && !empty( $_POST['new_matches'] ) ) { $data['matches'] = $_POST['new_matches']; } return $data; } /* Function that sets a message. */ function AP_setMessage( $msg, $type ) { $this->messages[] = array( $msg, $type ); } /* Function that gets, displays and clears all messages. */ function AP_getMessage() { $messages = ''; foreach( $this->messages as $message ){ $messages.= '
' . $message[0] . '' . __( 'Close', 'LDB_AP' ) . '
' . "\n"; } $this->messages = array(); echo $messages; } /* Function that gets all the info for a feed. */ function AP_getFeed( $id ) { global $wpdb; if( $id === null ) return false; $feed = $wpdb->get_row( 'SELECT * FROM ' . $wpdb->prefix . 'apfeeds WHERE id=' . $id, ARRAY_A ); return $feed; } /* Function that fetches the custom fields for matching the identifier to. */ function AP_getCustomFields() { $fields = array(); $products = get_posts( array( 'post_type' => 'product', 'post_status' => array( 'publish', 'draft' ) ) ); foreach( $products as $product ) { $fields = array_merge( $fields, get_post_custom_keys( $product->ID ) ); } foreach( $fields as $key => $field ) { if( $field[0] === '_' ) unset( $fields[ $key ] ); } $fields = array_unique( $fields ); return $fields; } /* Function to build a '; if( $split ) { foreach( $values as $key => $value ) { if( is_array( $value ) ) { $select.= ''; foreach( $value as $subkey => $subvalue ) { if( $subkey === $default ) { $select.= ''; } else { $select.= ''; } } $select.= ''; } else { if( $key === $default ) { $select.= ''; } else { $select.= ''; } } } } else { foreach( $values as $value ) { if( $value === $default ) { $select.= ''; } else { $select.= ''; } } } $select.= ''; return $select; } /* Function that processes a feed based on a feed ID. */ function AP_processFeed( $feed ) { global $wpdb; $info = json_decode( get_option( 'ap_feed_' . $feed, false ), true ); if( isset( $info['timestamp'] ) && $info['timestamp'] < ( time() - 300 ) ) { return $info['data']; } else { $info = array(); $feedinfo = $this->AP_getFeed( $feed ); $data = wp_remote_get( $feedinfo['url'] ); $body = new DOMDocument(); @$body->loadXML( $data['body'] ); $xpath = new DOMXPath( $body ); $items = $xpath->query( $feedinfo['item_xpath'] ); foreach ( $items as $item ) { $price = @$this->AP_getValue( @$xpath->query( $feedinfo['price_xpath'], $item ) ); $name = @$this->AP_getValue( @$xpath->query( $feedinfo['name_xpath'], $item ) ); $image = @$this->AP_getValue( @$xpath->query( $feedinfo['image_xpath'], $item ) ); $link = @$this->AP_getValue( @$xpath->query( $feedinfo['link_xpath'], $item ) ); $identifier = @$this->AP_getValue( @$xpath->query( $feedinfo['identifier_xpath'], $item ) ); $info[] = array( 'identifier' => $identifier, 'matches' => $feedinfo['matches'], 'currency' => $feedinfo['currency'], 'price' => $price, 'name' => $name, 'image' => $image, 'link' => $link, 'feed_id' => $feedinfo['ID'] ); } $option = array( 'data' => $info, 'time' => time() ); update_option( 'ap_feed_' . $feed, json_encode( $option ) ); return $info; } } /* Function that gets the value of an XPath node. */ function AP_getValue( $e ) { if( $e ) { return trim( preg_replace( '/\s+/', ' ', @$e->item(0)->nodeValue ) ); } else { return false; } } /* Function that processes the prices found for a product. */ function AP_processPrices( $feed ) { global $wpdb; $info = array(); $feedinfo = $this->AP_getFeed( $feed ); $wpdb->query( 'UPDATE ' . $wpdb->prefix . 'apprices SET online = 0 WHERE feedID = ' . $feedinfo['ID'] ); $info = @$this->AP_processFeed( $feed ); foreach( $info as $item ) { $query = 'SELECT wposts.ID FROM ' . $wpdb->posts . ' wposts, ' . $wpdb->postmeta . ' wpostmeta WHERE wposts.ID = wpostmeta.post_id AND wpostmeta.meta_key = "' . $item['matches'] . '" AND wpostmeta.meta_value = "' . $item['identifier'] . '" AND wposts.post_type = "product"'; $results = $wpdb->get_results( $query ); foreach( $results as $result ) { $data = array( 'productID' => $result->ID, 'feedID' => $item['feed_id'], 'price' => $item['price'], 'link' => $item['link'], 'online' => 1 ); $update = $wpdb->get_row( 'SELECT * FROM ' . $wpdb->prefix . 'apprices WHERE productID = ' . $result->ID . ' AND feedID = ' . $item['feed_id'] ); if( $update ) { $wpdb->update( $wpdb->prefix . 'apprices', $data, array( 'ID' => $update->ID ) ); } else { $wpdb->insert( $wpdb->prefix . 'apprices', $data ); } } } } /* Function that processes all the prices. For cron purposes. */ function AP_processAllPrices() { global $wpdb; $feeds = $wpdb->get_results( 'SELECT ID FROM ' . $wpdb->prefix . 'apfeeds ORDER BY ID ASC', ARRAY_A ); foreach( $feeds as $feed ) { $this->AP_processPrices( $feed['ID'] ); } } /* Function that builds a table to display the prices in the front-end. */ function AP_buildTable( $data ) { $table = ''; if( $data ) { foreach( $data as $row ){ $table.= ''; } } else { $table.= ''; } $table.= '
' . $row->title . '' . $row->price . '
' . __( 'No prices were found.', 'LDB_AP' ) . '
'; return $table; } /* Function that gets the prices to display the prices in the front-end. */ function AP_getPrices( $table = false ) { global $post, $wpdb; $results = $wpdb->get_results( 'SELECT apfeeds.title, apprices.price, apprices.link FROM ' . $wpdb->prefix . 'apprices apprices, ' . $wpdb->prefix . 'apfeeds apfeeds WHERE apprices.productID = ' . $post->ID . ' AND apprices.feedID = apfeeds.ID AND apprices.online = 1 ORDER BY apprices.price ASC' ); if ( $table ) $results = $this->AP_buildTable( $results ); return $results; } } }