Plugin Directory

Changeset 2042059


Ignore:
Timestamp:
03/01/2019 11:28:04 AM (7 years ago)
Author:
storespot
Message:

Version 1.1.0 release

Location:
storespot
Files:
2 added
18 edited
1 copied

Legend:

Unmodified
Added
Removed
  • storespot/tags/1.1.0/admin/class-storespot-api.php

    r1969706 r2042059  
    1616            'permission_callback' => array( $this, 'get_settings_permission_check' ),
    1717        ));
     18
     19        register_rest_route( $this->namespace, '/storespot/feed/', array(
     20            'methods'                       => WP_REST_SERVER::READABLE,
     21            'callback'                      => array( $this, 'update_storespot_feed' ),
     22            'permission_callback' => array( $this, 'get_settings_permission_check' ),
     23        ) );
    1824    }
    1925
     
    3036    }
    3137
    32     public function update_storespot_settings($request) {
    33         $settings = $request['settings'];
    34         update_option( 'storespot_settings', $settings );
    35         if ( ! wp_next_scheduled( 'stsp_product_feed_update' ) ) {
    36             wp_schedule_event( time(), 'hourly', 'stsp_product_feed_update' );
    37         }
    38 
    39         $data = array( 'updated' => true, 'settings' => get_option( 'storespot_settings' ) );
    40         $response = rest_ensure_response($data);
    41         $response->set_status(200);
    42 
    43         return $response;
    44     }
    45 
    4638    public function get_settings_permission_check() {
    4739        if ( !wc_rest_check_user_permissions('read') ) {
     
    5648    }
    5749
    58     public function get_storespot_settings($request) {
    59         if ( wp_next_scheduled( 'stsp_product_feed_update' ) ) {
    60             $cronjob = date(
    61                 'Y-m-d h:i:s',
    62                 wp_next_scheduled( 'stsp_product_feed_update' )
    63             );
    64         } else {
    65             $cronjob = false;
     50    public function update_storespot_settings($request) {
     51        $new_settings = $request['settings'];
     52        $current_settings = get_option( 'storespot_settings' );
     53
     54        foreach( $new_settings as $key => $value ) {
     55            $current_settings[$key] = $value;
    6656        }
    6757
    68         if ( ! function_exists( 'get_plugins' ) ) {
    69             require_once ABSPATH . 'wp-admin/includes/plugin.php';
    70         }
     58        $updated = update_option( 'storespot_settings', $current_settings );
     59        $data = array( 'updated' => $updated );
    7160
    72         $plugins = get_plugins();
    73         $plugins_view = array();
    74         foreach( $plugins as $plugin ) {
    75             array_push($plugins_view, array(
    76                 'name'      => $plugin['Name'],
    77                 'version' => $plugin['Version'],
    78             ));
    79         }
     61        $response = rest_ensure_response($data);
     62        $response->set_status(200);
     63        return $response;
     64    }
    8065
     66    public function get_storespot_settings($request) {
    8167        $data = array(
    82             'cronjob'               => $cronjob,
    83             'plugin_version'    => STORESPOT_VERSION,
    84             'settings'              => get_option( ' storespot_settings' ),
    85             'wp_version'            => get_bloginfo( 'version' ),
    86             'wc_version'            => get_option( 'woocommerce_version' ),
    87             'plugins'               => $plugins_view,
     68            'settings'      => get_option( 'storespot_settings' ),
     69            'feed'          => get_option( 'storespot_feed' ),
     70            'stsp_version'  => STORESPOT_VERSION,
     71            'wp_version'    => get_bloginfo( 'version' ),
     72            'wc_version'    => get_option( 'woocommerce_version' ),
    8873        );
    8974
    9075        $response = rest_ensure_response($data);
    9176        $response->set_status(200);
     77        return $response;
     78    }
    9279
     80    public function update_storespot_feed() {
     81        do_action('stsp_call_async_feed_update');
     82        $response = rest_ensure_response(array( 'received' => true ));
     83        $response->set_status(200);
    9384        return $response;
    9485    }
  • storespot/tags/1.1.0/admin/class-storespot-productfeed.php

    r1977618 r2042059  
    77        protected $feed_items   = null;
    88        protected $factory      = null;
    9         protected $url              = null;
     9        protected $url          = null;
     10        protected $writer       = null;
    1011        protected $chunk_size   = 0;
    11         protected $offset           = 0;
     12        protected $offset       = 0;
    1213        protected $settings     = array();
    13         protected $store            = array();
     14        protected $store        = array();
    1415
    1516        public function __construct() {
    1617
    1718            $this->chunk_size   = $this->stsp_get_chunk_size();
    18             $this->settings         = $this->stsp_get_settings();
    19             $this->store                = array(
     19            $this->settings     = $this->stsp_get_settings();
     20            $this->store        = array(
    2021                'name'  => get_bloginfo( 'name' ),
    2122                'url'       => get_site_url(),
     
    3233            $upload_dir = $this->upload_directory();
    3334            $dir_path   = $upload_dir['dir_path'];
    34             $path           = $upload_dir['file_path'];
     35            $path       = $upload_dir['file_path'];
    3536            $this->url  = $upload_dir['file_url'];
    3637
    37             if ( file_exists( $dir_path ) ) {
    38                 $fp = fopen( $path, 'w' );
    39                 fwrite( $fp, $this->stsp_create_feed() );
    40                 fclose( $fp );
    41             }
    42 
     38            $tmp = $path.".tmp";
     39            if (file_exists( $tmp )) {
     40                unlink( $tmp );
     41            }
     42
     43            if ( $this->settings['feed'] === true && file_exists( $dir_path ) ) {
     44                $this->stsp_create_feed($tmp);
     45            }
     46
     47            rename($path . ".tmp", $path);
    4348            return $this->url;
    4449        }
     
    4752
    4853            $wp_upload_dir  = wp_upload_dir();
    49             $basedir                = $wp_upload_dir['basedir'];
    50             $baseurl                = $wp_upload_dir['baseurl'];
     54            $basedir        = $wp_upload_dir['basedir'];
     55            $baseurl        = $wp_upload_dir['baseurl'];
    5156            $storespot_dir  = $basedir . '/storespot/';
    5257            $storespot_url  = $baseurl . '/storespot/';
     
    7378
    7479            $settings = array(
    75                 'pixel_id' => null,
    76                 'category' => null,
     80                'category'      => null,
     81                'feed'          => false,
     82                'start_memory'  => null,
     83                'end_memory'    => null,
    7784            );
    7885            $config = get_option( 'storespot_settings', array() );
     
    8188                    $settings['category'] = $config['product_category'];
    8289                }
    83                 if( array_key_exists( 'pixel_id', $config ) ) {
    84                     $settings['pixel_id'] = $config['pixel_id'];
     90                if( array_key_exists( 'feed_enabled', $config ) ) {
     91                    $settings['feed'] = $config['feed_enabled'];
    8592                }
    8693            }
     
    107114            if ( function_exists( 'wc_get_products' ) ) {
    108115                $args = array(
    109                     'status'  => array( 'publish' ),
    110                     'type'    => array( 'simple', 'variable', 'bundle', 'composite' ),
    111                     'offset' => $this->offset,
    112                     'limit' => $this->chunk_size,
     116                    'status'    => array( 'publish' ),
     117                    'offset'    => $this->offset,
     118                    'limit'     => $this->chunk_size,
    113119                );
    114120                return array( 'wc_get_products', $args );
    115121            } else {
    116122                $args = array(
    117                     'post_type'   => 'product',
    118                     'offset'      => $this->offset,
    119                     'numberposts' => $this->chunk_size,
     123                    'post_type'     => 'product',
     124                    'offset'        => $this->offset,
     125                    'numberposts'   => $this->chunk_size,
    120126                );
    121127                return array( 'get_posts', $args );
     
    124130        }
    125131
    126         private function stsp_create_feed() {
    127 
    128             // Log every feed start
    129             error_log(
    130                 "\n" . date('Y-m-d h:i:s'). " :: starting feed write",
    131                 3,
    132                 $this->log_file()
    133             );
    134 
    135             // Make header first
    136             $output  = "";
    137             $output .= $this->stsp_render_header();
    138 
    139             // Render entries
     132        private function stsp_create_feed($file) {
     133            error_log("\n".date('Y-m-d h:i:s')." :: starting feed write",3,$this->log_file());
     134
     135            $this->settings['start_memory'] = memory_get_peak_usage();
     136            $this->writer = new XMLWriter();
     137            $this->writer->openMemory();
     138            $this->writer->startDocument('1.0', 'UTF-8');
     139            $this->stsp_render_header();
     140
    140141            $this->factory = new WC_Product_Factory();
    141142            list($query, $args) = $this->stsp_create_query();
     
    144145            $products = $query( $args );
    145146            while ( count( $products ) ) {
    146 
    147147                // Process products in query
    148148                foreach ( $products as $product ) {
    149                     $output .= $this->stsp_render_entry( $product );
    150                 }
    151 
    152                 // Flush internal cache for memory optimization
    153                 if ( ! wp_using_ext_object_cache() ) {
    154                     wp_cache_flush();
     149                    $this->stsp_render_entry( $product );
    155150                }
    156151
     
    158153                $args['offset'] += $this->chunk_size;
    159154                $products = $query( $args );
    160             }
    161 
    162             // Make footer
    163             $output .= $this->stsp_render_footer();
    164 
    165             // Log every feed end
    166             error_log(
    167                 "\n" . date('Y-m-d h:i:s'). " :: completed feed write",
    168                 3,
    169                 $this->log_file()
    170             );
    171 
    172             return $output;
     155
     156                // Write & flush
     157                file_put_contents($file, $this->writer->flush(true), FILE_APPEND);
     158            }
     159
     160            $this->settings['end_memory'] = memory_get_peak_usage();
     161
     162            $this->stsp_render_footer();
     163            file_put_contents($file, $this->writer->flush(true), FILE_APPEND);
     164            error_log("\n".date('Y-m-d h:i:s')." :: completed feed write",3,$this->log_file());
    173165        }
    174166
    175167        private function stsp_render_header() {
    176 
    177             $header  = "";
    178             $header .= "<?xml version='1.0' encoding='UTF-8' ?>\n";
    179             $header .= "<feed xmlns='http://www.w3.org/2005/Atom' xmlns:g='http://base.google.com/ns/1.0'>\n";
    180             $header .= "  <title><![CDATA[" . $this->store['name'] . " - Facebook Product Feed]]></title>\n";
    181             $header .= "  <link rel='self' href='" . $this->url . "'/>\n";
    182             return $header;
    183 
     168            // Start feed
     169            $this->writer->startElement('feed');
     170            $this->writer->writeAttribute('xmlns', 'http://www.w3.org/2005/Atom');
     171            $this->writer->writeAttribute('xmlns:g', 'http://base.google.com/ns/1.0');
     172
     173            // Add title
     174            $this->writer->startElement('title');
     175            $this->writer->writeCData($this->store['name'] . " - Facebook Product Feed");
     176            $this->writer->endElement();
     177
     178            // Add link
     179            $this->writer->startElement('link');
     180            $this->writer->writeAttribute('rel', 'self');
     181            $this->writer->writeAttribute('href', $this->url);
     182            $this->writer->endElement();
    184183        }
    185184
    186185        private function stsp_render_footer() {
    187 
    188             return '</feed>';
     186            $this->writer->endElement();
     187            $this->writer->writeComment('Created: ' . date('Y-m-d H:i:s', time()));
     188            $this->writer->writeComment('Start memory: ' . round( $this->settings['start_memory'] / 1024 / 1024, 2 ) . ' MB');
     189            $this->writer->writeComment('End memory: ' . round( $this->settings['end_memory'] / 1024 / 1024, 2 ) . ' MB');
    189190
    190191        }
     
    219220        private function stsp_variable_product( $product ) {
    220221            $variations = $product->get_available_variations();
    221             $output = '';
    222222            foreach ( $variations as $variation ) {
    223223                $variation_id   = $variation['variation_id'];
    224224                $variation      = $this->factory->get_product( $variation_id );
    225                 $output .= $this->stsp_render_product( $variation, $product );
    226             }
    227             return $output;
     225                $this->stsp_render_product( $variation, $product );
     226            }
     227            return;
    228228        }
    229229
    230230        private function stsp_render_product( $product, $parent=null ) {
    231231
    232             $image_link     = $this->render_image_link( $product );
     232            $image_link = $this->render_image_link( $product );
    233233            if( ! $image_link ) {
    234234                if( ! $parent )
     
    243243            $product_id     = $product->get_id();
    244244            $product_sku    = $product->get_sku();
    245             $feed_id            = $product_sku ?
    246                                             $product_sku . '_' . $product_id :
    247                                             'wc_post_id_' . $product_id;
    248 
    249             $group_id       = $parent ? $parent->get_id() : null;
    250             $product_name   = $product->get_name();
    251             $product_price= $product->get_price() . ' ' . $this->settings['currency'];
     245            $feed_id        = 'stsp_' . $product_id;
     246
     247            $group_id       = $parent ? 'stsp_' . $parent->get_id() : null;
     248            $product_name   = ucwords(strtolower($product->get_name()));
     249            $product_price  = $product->get_price() . ' ' . $this->settings['currency'];
    252250            $description    = $this->render_description( $product );
    253             $availability = $this->render_availability( $product );
     251            $availability   = $this->render_availability( $product );
    254252            $condition      = 'new';
    255253            $image_link     = $this->render_image_link( $product );
    256254            $additional     = $this->render_additional_images( $product );
    257             $brand              = $this->render_brand( $product );
    258             $link                   = $this->render_product_link( $product );
     255            $brand          = $this->render_brand( $product_id );
     256            $link           = $this->render_product_link( $product );
    259257            $sale_price     =   ( $product->is_on_sale() && $product->get_sale_price() ) ?
    260                                             $product->get_sale_price() . ' ' . $this->settings['currency'] :
    261                                             null;
     258                                        $product->get_sale_price() . ' ' . $this->settings['currency'] :
     259                                        null;
    262260            $sale_from      = $product->get_date_on_sale_from();
    263             $sale_to            = $product->get_date_on_sale_to();
     261            $sale_to        = $product->get_date_on_sale_to();
    264262
    265263            // Fixes for product variations
     
    282280
    283281            // Render output
    284             $output  = "";
    285             $output .= "  <entry>\n";
    286             $output .= "    <g:id>" . $feed_id . "</g:id>\n";
    287             $output .= "    <g:title><![CDATA[" . $title . "]]></g:title>\n";
    288             $output .= "    <g:description><![CDATA[" . $description . "]]></g:description>\n";
    289             $output .= "    <g:availability>" . $availability . "</g:availability>\n";
    290             $output .= "    <g:condition>" . $condition . "</g:condition>\n";
    291             $output .= "    <g:link>" . $link . "</g:link>\n";
    292             $output .= "    <g:price>" . $product_price . "</g:price>\n";
    293             $output .= "    <g:brand><![CDATA[" . $brand . "]]></g:brand>\n";
    294             $output .= "    <g:image_link><![CDATA[" . $image_link . "]]></g:image_link>\n";
     282            $this->writer->startElement('entry');
     283            $this->writer->writeElement('g:id', $feed_id);
     284            $this->writer->startElement('g:title');$this->writer->writeCData($title);$this->writer->endElement();
     285            $this->writer->startElement('g:description');$this->writer->writeCData($description);$this->writer->endElement();
     286            $this->writer->writeElement('g:availability', $availability);
     287            $this->writer->writeElement('g:condition', $condition);
     288            $this->writer->writeElement('g:link', $link);
     289            $this->writer->writeElement('g:price', $product_price);
     290            $this->writer->startElement('g:brand');$this->writer->writeCData($brand);$this->writer->endElement();
     291            $this->writer->startElement('g:image_link');$this->writer->writeCData($image_link);$this->writer->endElement();
    295292
    296293            if( $group_id ) {
    297                 $output .= "    <g:item_group_id>" . $group_id . "</g:item_group_id>\n";
    298             }
    299 
    300             if( $additional_image_link ) {
    301                 $output .= "    <g:additional_image_link><![CDATA[" . $additional_image_link . "]]></g:additional_image_link>\n";
     294                $this->writer->writeElement('g:item_group_id', $group_id);
     295            }
     296
     297            if( $additional ) {
     298                $this->writer->startElement('g:additional_image_link');$this->writer->writeCData($additional);$this->writer->endElement();
    302299            }
    303300
    304301            if( $sale_price ) {
    305                 $output .= "    <g:sale_price><![CDATA[" . $sale_price . "]]></g:sale_price>\n";
     302                $this->writer->writeElement('g:sale_price', $sale_price);
    306303            }
    307304
    308305            if( $sale_from ) {
    309                 $output .= "    <g:sale_price_start_date><![CDATA[" . $sale_from . "]]></g:sale_price_start_date>\n";
     306                $this->writer->startElement('g:sale_price_start_date');$this->writer->writeCData($sale_from);$this->writer->endElement();
    310307            }
    311308
    312309            if( $sale_to ) {
    313                 $output .= "    <g:sale_price_end_date><![CDATA[" . $sale_to . "]]></g:sale_price_end_date>\n";
     310                $this->writer->startElement('g:sale_price_end_date');$this->writer->writeCData($sale_to);$this->writer->endElement();
    314311            }
    315312
    316313            if( $this->settings['category'] ) {
    317                 $output .= "    <g:google_product_category><![CDATA[" . $this->settings['category'] . "]]></g:google_product_category>\n";
    318             }
    319 
    320             $output .= "  </entry>\n";
    321 
    322             return $output;
     314                $this->writer->writeElement('g:google_product_category', $this->settings['category']);
     315            }
     316
     317            $this->writer->endElement();
     318            return;
    323319        }
    324320
     
    370366        private function render_additional_images( $product ) {
    371367            $gallery_image_ids = $product->get_gallery_image_ids();
     368            $additional_image_link = null;
    372369            if ( $gallery_image_ids ) {
    373370                $i = 0;
     
    406403        }
    407404
    408         private function render_brand( $product ) {
     405        private function render_brand( $product_id ) {
    409406            $term_names = wp_get_post_terms(
    410407                $product_id, 'brand', array('orderby'=>'name', 'fields' => 'names')
  • storespot/tags/1.1.0/includes/class-storespot-activator.php

    r1957373 r2042059  
    77        $stsp_settings = get_option('storespot_settings');
    88
    9         if( $stsp_settings && array_key_exists( 'product_feed', $stsp_settings )) {
    10             $feed = $stsp_settings['product_feed'];
    11             if ( $feed && !wp_next_scheduled( 'stsp_product_feed_update' ) ) {
    12                 wp_schedule_event( time(), 'hourly', 'stsp_product_feed_update' );
    13             }
    14         } else {
     9        if( !$stsp_settings ) {
    1510            $options = [
    16                 'pixel_id' => '',
    17                 'product_feed' => 'no',
    18                 'product_category' => ''
     11                'pixel_id' => null,
     12                'pixel_enabled' => false,
     13                'feed_enabled' => false,
     14                'product_category' => 0,
    1915            ];
    20 
    2116            add_option( 'storespot_settings', $options );
     17            add_option( 'storespot_feed', null );
    2218        }
    2319
  • storespot/tags/1.1.0/includes/class-storespot-deactivator.php

    r1977618 r2042059  
    22class StoreSpot_Deactivator {
    33    public static function deactivate() {
    4         wp_clear_scheduled_hook( 'stsp_product_feed_update' );
    54        delete_option( 'storespot_settings' );
     5        delete_option( 'storespot_feed' );
    66    }
    77}
  • storespot/tags/1.1.0/includes/class-storespot.php

    r1977618 r2042059  
    2222            $this->version = STORESPOT_VERSION;
    2323        } else {
    24             $this->version = '1.0.0';
     24            $this->version = '0.0.0';
    2525        }
    2626        $this->plugin_name = 'storespot';
     
    4646        require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/class-storespot-messages.php';
    4747        require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/class-storespot-api.php';
     48        require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/class-storespot-async.php';
    4849        require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-storespot-events.php';
    4950        require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-storespot-facebook-pixel.php';
     
    5556            ! class_exists( 'StoreSpot_API' ) ||
    5657            ! class_exists( 'StoreSpot_Events' ) ||
    57             ! class_exists( 'StoreSpot_Facebook_Pixel' )
     58            ! class_exists( 'StoreSpot_Facebook_Pixel' ) ||
     59            ! class_exists( 'StoreSpot_Async' )
    5860        ) {
    5961            return false;
     
    6567
    6668    private function define_admin_hooks() {
    67             $product_feed = new StoreSpot_Product_Feed();
    6869            $admin_message = new StoreSpot_Messages();
    69             $this->loader->add_action( 'stsp_product_feed_update', $product_feed, 'write_product_feed' );
     70            $async_request = new StoreSpot_Async();
     71            $products_feed = new StoreSpot_Product_Feed();
    7072            $this->loader->add_action( 'admin_notices', $admin_message, 'activation_notice' );
     73            $this->loader->add_action( 'wp_ajax_' . $async_request->get_ajax_action(), $async_request, 'execute' );
     74            $this->loader->add_action( 'wp_ajax_nopriv_' . $async_request->get_ajax_action(), $async_request, 'execute' );
     75            $this->loader->add_action( 'stsp_call_async_feed_update', $async_request, 'call' );
     76            $this->loader->add_action( $async_request->get_feed_action(), $products_feed, 'write_product_feed' );
    7177    }
    7278
     
    7480        $plugin_public = new StoreSpot_Events( $this->get_plugin_name(), $this->get_version() );
    7581        $pixel_id = $plugin_public->facebook_pixel->get_pixel_id();
    76         if( $pixel_id && ! $this->fb_integration_installed( $pixel_id ) ) {
     82        if( $pixel_id ) {
    7783            $this->loader->add_action( 'wp_head', $plugin_public, 'render_facebook_pixel' );
    78             $this->loader->add_action( 'wp_head', $plugin_public, 'render_facebook_pixel_noscript' );
     84            $this->loader->add_action( 'wp_footer', $plugin_public, 'render_facebook_pixel_noscript' );
    7985            $this->loader->add_action( 'woocommerce_after_single_product', $plugin_public, 'render_product_view_event');
    8086            $this->loader->add_action( 'woocommerce_after_shop_loop', $plugin_public, 'render_category_view_event');
     
    8490            $this->loader->add_action( 'woocommerce_after_checkout_form', $plugin_public, 'render_initiate_checkout_event' );
    8591            $this->loader->add_action( 'woocommerce_thankyou', $plugin_public, 'render_purchase_event' );
     92            $this->loader->add_action( 'woocommerce_payment_complete', $plugin_public, 'render_purchase_event' );
    8693            $this->loader->add_action( 'wp_footer', $plugin_public, 'custom_jquery_add_to_cart_script' );
    87             $this->loader->add_action( 'wc_ajax_render_add_to_cart_event', $plugin_public, 'render_ajax_add_to_cart_event' );
     94            $this->loader->add_action( 'wc_ajax_stsp_add_to_cart_event', $plugin_public, 'render_ajax_add_to_cart_event' );
    8895        }
    8996    }
    9097
    91     private function fb_integration_installed($pixel_id) {
    92         $fb_option = get_option('facebook_config');
    93         $fb_integration_option_set = false;
    94         if ( $fb_option && array_key_exists( 'pixel_id', $fb_option ) ) {
    95             if ( $fb_option['pixel_id'] == $pixel_id) {
    96                 $fb_integration_option_set = true;
    97             }
    98         }
    99         include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
    100         $fb_integration_activated = class_exists('WC_Facebookcommerce');
    101         return $fb_integration_activated && $fb_integration_option_set;
    102     }
    103 
    10498    private function define_api_hooks() {
    105             $api = new StoreSpot_API();
    106             $this->loader->add_action( 'rest_api_init', $api, 'storespot_api_route');
     99        $api = new StoreSpot_API();
     100        $this->loader->add_action( 'rest_api_init', $api, 'storespot_api_route');
    107101    }
    108102
  • storespot/tags/1.1.0/public/class-storespot-events.php

    r1982419 r2042059  
    1818    public function get_facebook_content_id($product) {
    1919        $product_id = $product->get_id();
    20         $product_sku = $product->get_sku();
    21         $sku_id = $product_sku . '_' . $product_id;
    22         $other_id = 'wc_post_id_' . $product_id;
    23 
    24         $ids = array($other_id, $product_id);
    25         if ( $product_sku ) {
    26             $ids[] = $sku_id;
    27             $ids[] = $product_sku;
    28         }
    29 
    30         return $ids;
     20        return 'stsp_' . $product->get_id();
    3121    }
    3222
     
    3424        global $post;
    3525        $product = wc_get_product($post->ID);
     26        $content_type = 'product';
    3627
    3728        if ( $product ) {
     29            if( $product->get_type() == 'variable' ) {
     30                $content_type = 'product_group';
     31            }
    3832            $params = array();
     33            $params['content_ids'] = json_encode( [$this->get_facebook_content_id( $product )] );
     34            $params['content_type'] = $content_type;
     35            $params['content_name'] = $product->get_title();
     36            $params['currency'] = get_woocommerce_currency();
    3937            $params['value'] = $product->get_price();
    40             $params['content_name'] = $product->get_title();
    41             $params['content_type'] = ($product->get_type() == 'variable' ? 'product_group' : 'product');
    42             $params['currency'] = get_woocommerce_currency();
    43             $params['content_ids'] = json_encode( $this->get_facebook_content_id( $product ) );
    4438
    4539            $this->facebook_pixel->event_code( 'ViewContent', $params );
     
    5347
    5448        $products = array_values(array_map(function($item) {
    55         return wc_get_product($item->ID);
    56     }, $wp_query->posts));
     49            return wc_get_product($item->ID);
     50        }, $wp_query->posts));
    5751
    5852        $content_type = 'product';
     
    6054        foreach ($products as $product) {
    6155            if (!$product) { continue; }
    62             $product_ids = array_merge(
    63                 $product_ids,
    64                 $this->get_facebook_content_id($product)
    65             );
    66             if ($product->get_type() == 'variable') {
    67                 $content_type = 'product_group';
    68             }
    69     }
    70 
    71     $category_path = wp_get_post_terms( get_the_ID(), 'product_cat' );
     56            if ( $product->get_type() == 'variable' ) { continue; }
     57            $product_ids[] = $this->get_facebook_content_id($product);
     58        }
     59
     60        $category_path = wp_get_post_terms( get_the_ID(), 'product_cat' );
    7261        $content_category = array_values( array_map( function($item) {
    7362            return $item->name;
     
    8170
    8271        $params = array(
    83             'content_name'          => json_encode($categories['name']),
     72            'content_name'      => json_encode($categories['name']),
    8473            'content_category'  => json_encode($categories['categories']),
    85             'content_ids'           => json_encode(array_slice($product_ids, 0, 10)),
    86             'content_type'          => $content_type
     74            'content_ids'       => json_encode($product_ids),
     75            'content_type'      => $content_type
    8776        );
    8877
     
    112101        $product_ids = array();
    113102        foreach ( $products as $item ) {
    114             $product_ids = array_merge(
    115         $product_ids,
    116         $this->get_facebook_content_id( $item['data'] )
    117             );
     103            $product_ids[] = $this->get_facebook_content_id( $item['data'] );
    118104        }
    119105
     
    134120
    135121    public function render_ajax_add_to_cart_event() {
     122
    136123        global $woocommerce;
    137124        $products = $woocommerce->cart->get_cart();
     125
     126        ob_start();
     127
    138128        $product_ids = array();
    139129        foreach ( $products as $item ) {
    140             $product_ids = array_merge(
    141         $product_ids,
    142         $this->get_facebook_content_id( $item['data'] )
    143             );
    144         }
     130            $product_ids[] = $this->get_facebook_content_id( $item['data'] );
     131        }
     132
    145133        $params = array();
    146134        $params['content_ids'] = json_encode( $product_ids );
     
    149137        $params['currency'] = get_woocommerce_currency();
    150138
    151         $code = $this->facebook_pixel->ajax_event_code( 'AddToCart', $params );
    152         wp_send_json($code);
     139        echo $this->facebook_pixel->ajax_event_code( 'AddToCart', $params );
     140
     141        $pixel = ob_get_clean();
     142        wp_send_json($pixel);
    153143    }
    154144
     
    162152        $product_ids = array();
    163153        foreach ( $products as $item ) {
    164             $product_ids = array_merge(
    165         $product_ids,
    166         $this->get_facebook_content_id( $item['data'] )
    167             );
     154            $product_id[] = $this->get_facebook_content_id( $item['data'] );
    168155        }
    169156
     
    184171
    185172        $order = wc_get_order( $order_id );
     173        $content_type = 'product';
    186174        $product_ids = array();
    187175        foreach ( $order->get_items() as $item ) {
    188176            $product = $item->get_product();
    189             $product_ids = array_merge(
    190         $product_ids,
    191         $this->get_facebook_content_id( $product )
    192             );
    193         }
    194 
    195         $params = array();
    196         $params['content_ids'] = json_encode( $product_ids );
    197         $params['content_type'] = 'product';
     177            $product_ids[] = $this->get_facebook_content_id( $product );
     178            if( $product->get_type() == 'variable' ) {
     179                $content_type = 'product_group';
     180            }
     181        }
     182
     183        $params = array();
     184        $params['content_ids'] = json_encode( $product_ids );
     185        $params['content_type'] = $content_type;
    198186        $params['value'] = $order->get_total();
    199187        $params['currency'] = get_woocommerce_currency();
     
    203191
    204192    public function custom_jquery_add_to_cart_script(){
    205         if ( is_shop() || is_product_category() || is_product_tag() ):
    206         ?>
    207             <script type="text/javascript">
    208                 (function($){
    209                     $( document.body ).on( 'added_to_cart', function(){
    210                         $.get('?wc-ajax=render_add_to_cart_event', function(script) {
    211                             console.log(script);
    212                             $('head').append(script);
    213                         });
    214                     });
    215                 })(jQuery);
    216             </script>
    217             <?php
    218         endif;
     193        if ( is_front_page() || is_shop() || is_product_category() || is_product_tag() ) {
     194
     195            echo "
     196<!-- StoreSpot Facebook Listener Begin -->
     197<script type='text/javascript'>
     198document.addEventListener('DOMContentLoaded', function() {
     199  jQuery && jQuery(function($){
     200    $('body').on('added_to_cart', function(event) {
     201      // Ajax action.
     202      $.get('?wc-ajax=stsp_add_to_cart_event', function(data) {
     203        $('head').append(data);
     204      });
     205    });
     206  });
     207}, false);
     208</script>
     209<!-- StoreSpot Facebook Listener End -->
     210            ";
     211
     212        }
    219213    }
    220214}
  • storespot/tags/1.1.0/public/class-storespot-facebook-pixel.php

    r1969706 r2042059  
    4040    public function get_pixel_id() {
    4141        $stsp_settings = get_option( 'storespot_settings' );
    42         if( $stsp_settings && array_key_exists( 'pixel_id', $stsp_settings )) {
     42        if(
     43            $stsp_settings
     44            && array_key_exists( 'pixel_id', $stsp_settings )
     45            && array_key_exists( 'pixel_enabled', $stsp_settings )
     46            && $stsp_settings['pixel_enabled'] === true
     47            && $stsp_settings['pixel_id'] !== null
     48        ) {
    4349            return $stsp_settings['pixel_id'];
    4450        }
  • storespot/tags/1.1.0/readme.txt

    r1982419 r2042059  
    33Tags: woocommerce, facebook, dynamic ads, retargeting, woocommerce marketing, remarketing
    44Requires at least: 4.4.0
    5 Tested up to: 4.9
     5Tested up to: 5.1
    66Requires PHP: 5.6
    7 Stable tag: 1.0.10
     7Stable tag: 1.1.0
    88License: GPLv2 or later
    99License URI: http://www.gnu.org/licenses/gpl-2.0.html
     
    5050== Changelog ==
    5151
    52 = 1.0.10 =
    53 * Bug fixes for add to cart events and purchase events
    54 * Support for combined category events
     52= 1.1.0 =
     53* Fix add-to-cart events with ajax
     54* Improved product and category matching
     55* Improved memory usage in feed generation
    5556
    56 = 1.0.9 =
    57 * Add category view to pixel data
    58 * Remove options after plugin deactivation
    59 
    60 = 1.0.8 =
    61 * Improve memory usage in feed generation
    62 
    63 = 1.0.7 =
    64 * Compatibility with Facebook for WooCommerce plugin
    65 
    66 = 1.0.6 =
    67 * Use pagination on feed generation
    68 
    69 = 1.0.5 =
    70 * Add registration button to welcome message
    71 * Add error handling and default fields in product feed
    72 
    73 = 1.0.4 =
    74 * Fix product feed encoding
    75 * Add brand names to feed
    76 
    77 = 1.0.3 =
    78 * Extended admin notices
    79 * Add integration with official Facebook plugin
    80 
    81 = 1.0.2 =
    82 * Upgrade WooCommerce REST API to v2
    83 
    84 = 1.0.1 =
    85 * Update description.
    86 * Add plugin banner.
    87 * Rename plugin.
    88 
    89 = 1.0.0 =
    90 * Initial release.
     57= 1.0 =
     58* Beta release
  • storespot/tags/1.1.0/storespot.php

    r1982419 r2042059  
    44 * Plugin URI:   https://storespot.io/
    55 * Description:  Stop leaving money on the table. Automate your retargeting ads with StoreSpot.
    6  * Version:      1.0.10
     6 * Version:      1.1.0
    77 * Author:       StoreSpot
    88**/
     
    1111if ( ! defined( 'WPINC' ) ) { die; }
    1212
    13 define( 'STORESPOT_VERSION', '1.0.10' );
     13define( 'STORESPOT_VERSION', '1.1.0' );
    1414
    1515function activate_storespot() {
  • storespot/trunk/admin/class-storespot-api.php

    r1969706 r2042059  
    1616            'permission_callback' => array( $this, 'get_settings_permission_check' ),
    1717        ));
     18
     19        register_rest_route( $this->namespace, '/storespot/feed/', array(
     20            'methods'                       => WP_REST_SERVER::READABLE,
     21            'callback'                      => array( $this, 'update_storespot_feed' ),
     22            'permission_callback' => array( $this, 'get_settings_permission_check' ),
     23        ) );
    1824    }
    1925
     
    3036    }
    3137
    32     public function update_storespot_settings($request) {
    33         $settings = $request['settings'];
    34         update_option( 'storespot_settings', $settings );
    35         if ( ! wp_next_scheduled( 'stsp_product_feed_update' ) ) {
    36             wp_schedule_event( time(), 'hourly', 'stsp_product_feed_update' );
    37         }
    38 
    39         $data = array( 'updated' => true, 'settings' => get_option( 'storespot_settings' ) );
    40         $response = rest_ensure_response($data);
    41         $response->set_status(200);
    42 
    43         return $response;
    44     }
    45 
    4638    public function get_settings_permission_check() {
    4739        if ( !wc_rest_check_user_permissions('read') ) {
     
    5648    }
    5749
    58     public function get_storespot_settings($request) {
    59         if ( wp_next_scheduled( 'stsp_product_feed_update' ) ) {
    60             $cronjob = date(
    61                 'Y-m-d h:i:s',
    62                 wp_next_scheduled( 'stsp_product_feed_update' )
    63             );
    64         } else {
    65             $cronjob = false;
     50    public function update_storespot_settings($request) {
     51        $new_settings = $request['settings'];
     52        $current_settings = get_option( 'storespot_settings' );
     53
     54        foreach( $new_settings as $key => $value ) {
     55            $current_settings[$key] = $value;
    6656        }
    6757
    68         if ( ! function_exists( 'get_plugins' ) ) {
    69             require_once ABSPATH . 'wp-admin/includes/plugin.php';
    70         }
     58        $updated = update_option( 'storespot_settings', $current_settings );
     59        $data = array( 'updated' => $updated );
    7160
    72         $plugins = get_plugins();
    73         $plugins_view = array();
    74         foreach( $plugins as $plugin ) {
    75             array_push($plugins_view, array(
    76                 'name'      => $plugin['Name'],
    77                 'version' => $plugin['Version'],
    78             ));
    79         }
     61        $response = rest_ensure_response($data);
     62        $response->set_status(200);
     63        return $response;
     64    }
    8065
     66    public function get_storespot_settings($request) {
    8167        $data = array(
    82             'cronjob'               => $cronjob,
    83             'plugin_version'    => STORESPOT_VERSION,
    84             'settings'              => get_option( ' storespot_settings' ),
    85             'wp_version'            => get_bloginfo( 'version' ),
    86             'wc_version'            => get_option( 'woocommerce_version' ),
    87             'plugins'               => $plugins_view,
     68            'settings'      => get_option( 'storespot_settings' ),
     69            'feed'          => get_option( 'storespot_feed' ),
     70            'stsp_version'  => STORESPOT_VERSION,
     71            'wp_version'    => get_bloginfo( 'version' ),
     72            'wc_version'    => get_option( 'woocommerce_version' ),
    8873        );
    8974
    9075        $response = rest_ensure_response($data);
    9176        $response->set_status(200);
     77        return $response;
     78    }
    9279
     80    public function update_storespot_feed() {
     81        do_action('stsp_call_async_feed_update');
     82        $response = rest_ensure_response(array( 'received' => true ));
     83        $response->set_status(200);
    9384        return $response;
    9485    }
  • storespot/trunk/admin/class-storespot-productfeed.php

    r1977618 r2042059  
    77        protected $feed_items   = null;
    88        protected $factory      = null;
    9         protected $url              = null;
     9        protected $url          = null;
     10        protected $writer       = null;
    1011        protected $chunk_size   = 0;
    11         protected $offset           = 0;
     12        protected $offset       = 0;
    1213        protected $settings     = array();
    13         protected $store            = array();
     14        protected $store        = array();
    1415
    1516        public function __construct() {
    1617
    1718            $this->chunk_size   = $this->stsp_get_chunk_size();
    18             $this->settings         = $this->stsp_get_settings();
    19             $this->store                = array(
     19            $this->settings     = $this->stsp_get_settings();
     20            $this->store        = array(
    2021                'name'  => get_bloginfo( 'name' ),
    2122                'url'       => get_site_url(),
     
    3233            $upload_dir = $this->upload_directory();
    3334            $dir_path   = $upload_dir['dir_path'];
    34             $path           = $upload_dir['file_path'];
     35            $path       = $upload_dir['file_path'];
    3536            $this->url  = $upload_dir['file_url'];
    3637
    37             if ( file_exists( $dir_path ) ) {
    38                 $fp = fopen( $path, 'w' );
    39                 fwrite( $fp, $this->stsp_create_feed() );
    40                 fclose( $fp );
    41             }
    42 
     38            $tmp = $path.".tmp";
     39            if (file_exists( $tmp )) {
     40                unlink( $tmp );
     41            }
     42
     43            if ( $this->settings['feed'] === true && file_exists( $dir_path ) ) {
     44                $this->stsp_create_feed($tmp);
     45            }
     46
     47            rename($path . ".tmp", $path);
    4348            return $this->url;
    4449        }
     
    4752
    4853            $wp_upload_dir  = wp_upload_dir();
    49             $basedir                = $wp_upload_dir['basedir'];
    50             $baseurl                = $wp_upload_dir['baseurl'];
     54            $basedir        = $wp_upload_dir['basedir'];
     55            $baseurl        = $wp_upload_dir['baseurl'];
    5156            $storespot_dir  = $basedir . '/storespot/';
    5257            $storespot_url  = $baseurl . '/storespot/';
     
    7378
    7479            $settings = array(
    75                 'pixel_id' => null,
    76                 'category' => null,
     80                'category'      => null,
     81                'feed'          => false,
     82                'start_memory'  => null,
     83                'end_memory'    => null,
    7784            );
    7885            $config = get_option( 'storespot_settings', array() );
     
    8188                    $settings['category'] = $config['product_category'];
    8289                }
    83                 if( array_key_exists( 'pixel_id', $config ) ) {
    84                     $settings['pixel_id'] = $config['pixel_id'];
     90                if( array_key_exists( 'feed_enabled', $config ) ) {
     91                    $settings['feed'] = $config['feed_enabled'];
    8592                }
    8693            }
     
    107114            if ( function_exists( 'wc_get_products' ) ) {
    108115                $args = array(
    109                     'status'  => array( 'publish' ),
    110                     'type'    => array( 'simple', 'variable', 'bundle', 'composite' ),
    111                     'offset' => $this->offset,
    112                     'limit' => $this->chunk_size,
     116                    'status'    => array( 'publish' ),
     117                    'offset'    => $this->offset,
     118                    'limit'     => $this->chunk_size,
    113119                );
    114120                return array( 'wc_get_products', $args );
    115121            } else {
    116122                $args = array(
    117                     'post_type'   => 'product',
    118                     'offset'      => $this->offset,
    119                     'numberposts' => $this->chunk_size,
     123                    'post_type'     => 'product',
     124                    'offset'        => $this->offset,
     125                    'numberposts'   => $this->chunk_size,
    120126                );
    121127                return array( 'get_posts', $args );
     
    124130        }
    125131
    126         private function stsp_create_feed() {
    127 
    128             // Log every feed start
    129             error_log(
    130                 "\n" . date('Y-m-d h:i:s'). " :: starting feed write",
    131                 3,
    132                 $this->log_file()
    133             );
    134 
    135             // Make header first
    136             $output  = "";
    137             $output .= $this->stsp_render_header();
    138 
    139             // Render entries
     132        private function stsp_create_feed($file) {
     133            error_log("\n".date('Y-m-d h:i:s')." :: starting feed write",3,$this->log_file());
     134
     135            $this->settings['start_memory'] = memory_get_peak_usage();
     136            $this->writer = new XMLWriter();
     137            $this->writer->openMemory();
     138            $this->writer->startDocument('1.0', 'UTF-8');
     139            $this->stsp_render_header();
     140
    140141            $this->factory = new WC_Product_Factory();
    141142            list($query, $args) = $this->stsp_create_query();
     
    144145            $products = $query( $args );
    145146            while ( count( $products ) ) {
    146 
    147147                // Process products in query
    148148                foreach ( $products as $product ) {
    149                     $output .= $this->stsp_render_entry( $product );
    150                 }
    151 
    152                 // Flush internal cache for memory optimization
    153                 if ( ! wp_using_ext_object_cache() ) {
    154                     wp_cache_flush();
     149                    $this->stsp_render_entry( $product );
    155150                }
    156151
     
    158153                $args['offset'] += $this->chunk_size;
    159154                $products = $query( $args );
    160             }
    161 
    162             // Make footer
    163             $output .= $this->stsp_render_footer();
    164 
    165             // Log every feed end
    166             error_log(
    167                 "\n" . date('Y-m-d h:i:s'). " :: completed feed write",
    168                 3,
    169                 $this->log_file()
    170             );
    171 
    172             return $output;
     155
     156                // Write & flush
     157                file_put_contents($file, $this->writer->flush(true), FILE_APPEND);
     158            }
     159
     160            $this->settings['end_memory'] = memory_get_peak_usage();
     161
     162            $this->stsp_render_footer();
     163            file_put_contents($file, $this->writer->flush(true), FILE_APPEND);
     164            error_log("\n".date('Y-m-d h:i:s')." :: completed feed write",3,$this->log_file());
    173165        }
    174166
    175167        private function stsp_render_header() {
    176 
    177             $header  = "";
    178             $header .= "<?xml version='1.0' encoding='UTF-8' ?>\n";
    179             $header .= "<feed xmlns='http://www.w3.org/2005/Atom' xmlns:g='http://base.google.com/ns/1.0'>\n";
    180             $header .= "  <title><![CDATA[" . $this->store['name'] . " - Facebook Product Feed]]></title>\n";
    181             $header .= "  <link rel='self' href='" . $this->url . "'/>\n";
    182             return $header;
    183 
     168            // Start feed
     169            $this->writer->startElement('feed');
     170            $this->writer->writeAttribute('xmlns', 'http://www.w3.org/2005/Atom');
     171            $this->writer->writeAttribute('xmlns:g', 'http://base.google.com/ns/1.0');
     172
     173            // Add title
     174            $this->writer->startElement('title');
     175            $this->writer->writeCData($this->store['name'] . " - Facebook Product Feed");
     176            $this->writer->endElement();
     177
     178            // Add link
     179            $this->writer->startElement('link');
     180            $this->writer->writeAttribute('rel', 'self');
     181            $this->writer->writeAttribute('href', $this->url);
     182            $this->writer->endElement();
    184183        }
    185184
    186185        private function stsp_render_footer() {
    187 
    188             return '</feed>';
     186            $this->writer->endElement();
     187            $this->writer->writeComment('Created: ' . date('Y-m-d H:i:s', time()));
     188            $this->writer->writeComment('Start memory: ' . round( $this->settings['start_memory'] / 1024 / 1024, 2 ) . ' MB');
     189            $this->writer->writeComment('End memory: ' . round( $this->settings['end_memory'] / 1024 / 1024, 2 ) . ' MB');
    189190
    190191        }
     
    219220        private function stsp_variable_product( $product ) {
    220221            $variations = $product->get_available_variations();
    221             $output = '';
    222222            foreach ( $variations as $variation ) {
    223223                $variation_id   = $variation['variation_id'];
    224224                $variation      = $this->factory->get_product( $variation_id );
    225                 $output .= $this->stsp_render_product( $variation, $product );
    226             }
    227             return $output;
     225                $this->stsp_render_product( $variation, $product );
     226            }
     227            return;
    228228        }
    229229
    230230        private function stsp_render_product( $product, $parent=null ) {
    231231
    232             $image_link     = $this->render_image_link( $product );
     232            $image_link = $this->render_image_link( $product );
    233233            if( ! $image_link ) {
    234234                if( ! $parent )
     
    243243            $product_id     = $product->get_id();
    244244            $product_sku    = $product->get_sku();
    245             $feed_id            = $product_sku ?
    246                                             $product_sku . '_' . $product_id :
    247                                             'wc_post_id_' . $product_id;
    248 
    249             $group_id       = $parent ? $parent->get_id() : null;
    250             $product_name   = $product->get_name();
    251             $product_price= $product->get_price() . ' ' . $this->settings['currency'];
     245            $feed_id        = 'stsp_' . $product_id;
     246
     247            $group_id       = $parent ? 'stsp_' . $parent->get_id() : null;
     248            $product_name   = ucwords(strtolower($product->get_name()));
     249            $product_price  = $product->get_price() . ' ' . $this->settings['currency'];
    252250            $description    = $this->render_description( $product );
    253             $availability = $this->render_availability( $product );
     251            $availability   = $this->render_availability( $product );
    254252            $condition      = 'new';
    255253            $image_link     = $this->render_image_link( $product );
    256254            $additional     = $this->render_additional_images( $product );
    257             $brand              = $this->render_brand( $product );
    258             $link                   = $this->render_product_link( $product );
     255            $brand          = $this->render_brand( $product_id );
     256            $link           = $this->render_product_link( $product );
    259257            $sale_price     =   ( $product->is_on_sale() && $product->get_sale_price() ) ?
    260                                             $product->get_sale_price() . ' ' . $this->settings['currency'] :
    261                                             null;
     258                                        $product->get_sale_price() . ' ' . $this->settings['currency'] :
     259                                        null;
    262260            $sale_from      = $product->get_date_on_sale_from();
    263             $sale_to            = $product->get_date_on_sale_to();
     261            $sale_to        = $product->get_date_on_sale_to();
    264262
    265263            // Fixes for product variations
     
    282280
    283281            // Render output
    284             $output  = "";
    285             $output .= "  <entry>\n";
    286             $output .= "    <g:id>" . $feed_id . "</g:id>\n";
    287             $output .= "    <g:title><![CDATA[" . $title . "]]></g:title>\n";
    288             $output .= "    <g:description><![CDATA[" . $description . "]]></g:description>\n";
    289             $output .= "    <g:availability>" . $availability . "</g:availability>\n";
    290             $output .= "    <g:condition>" . $condition . "</g:condition>\n";
    291             $output .= "    <g:link>" . $link . "</g:link>\n";
    292             $output .= "    <g:price>" . $product_price . "</g:price>\n";
    293             $output .= "    <g:brand><![CDATA[" . $brand . "]]></g:brand>\n";
    294             $output .= "    <g:image_link><![CDATA[" . $image_link . "]]></g:image_link>\n";
     282            $this->writer->startElement('entry');
     283            $this->writer->writeElement('g:id', $feed_id);
     284            $this->writer->startElement('g:title');$this->writer->writeCData($title);$this->writer->endElement();
     285            $this->writer->startElement('g:description');$this->writer->writeCData($description);$this->writer->endElement();
     286            $this->writer->writeElement('g:availability', $availability);
     287            $this->writer->writeElement('g:condition', $condition);
     288            $this->writer->writeElement('g:link', $link);
     289            $this->writer->writeElement('g:price', $product_price);
     290            $this->writer->startElement('g:brand');$this->writer->writeCData($brand);$this->writer->endElement();
     291            $this->writer->startElement('g:image_link');$this->writer->writeCData($image_link);$this->writer->endElement();
    295292
    296293            if( $group_id ) {
    297                 $output .= "    <g:item_group_id>" . $group_id . "</g:item_group_id>\n";
    298             }
    299 
    300             if( $additional_image_link ) {
    301                 $output .= "    <g:additional_image_link><![CDATA[" . $additional_image_link . "]]></g:additional_image_link>\n";
     294                $this->writer->writeElement('g:item_group_id', $group_id);
     295            }
     296
     297            if( $additional ) {
     298                $this->writer->startElement('g:additional_image_link');$this->writer->writeCData($additional);$this->writer->endElement();
    302299            }
    303300
    304301            if( $sale_price ) {
    305                 $output .= "    <g:sale_price><![CDATA[" . $sale_price . "]]></g:sale_price>\n";
     302                $this->writer->writeElement('g:sale_price', $sale_price);
    306303            }
    307304
    308305            if( $sale_from ) {
    309                 $output .= "    <g:sale_price_start_date><![CDATA[" . $sale_from . "]]></g:sale_price_start_date>\n";
     306                $this->writer->startElement('g:sale_price_start_date');$this->writer->writeCData($sale_from);$this->writer->endElement();
    310307            }
    311308
    312309            if( $sale_to ) {
    313                 $output .= "    <g:sale_price_end_date><![CDATA[" . $sale_to . "]]></g:sale_price_end_date>\n";
     310                $this->writer->startElement('g:sale_price_end_date');$this->writer->writeCData($sale_to);$this->writer->endElement();
    314311            }
    315312
    316313            if( $this->settings['category'] ) {
    317                 $output .= "    <g:google_product_category><![CDATA[" . $this->settings['category'] . "]]></g:google_product_category>\n";
    318             }
    319 
    320             $output .= "  </entry>\n";
    321 
    322             return $output;
     314                $this->writer->writeElement('g:google_product_category', $this->settings['category']);
     315            }
     316
     317            $this->writer->endElement();
     318            return;
    323319        }
    324320
     
    370366        private function render_additional_images( $product ) {
    371367            $gallery_image_ids = $product->get_gallery_image_ids();
     368            $additional_image_link = null;
    372369            if ( $gallery_image_ids ) {
    373370                $i = 0;
     
    406403        }
    407404
    408         private function render_brand( $product ) {
     405        private function render_brand( $product_id ) {
    409406            $term_names = wp_get_post_terms(
    410407                $product_id, 'brand', array('orderby'=>'name', 'fields' => 'names')
  • storespot/trunk/includes/class-storespot-activator.php

    r1957373 r2042059  
    77        $stsp_settings = get_option('storespot_settings');
    88
    9         if( $stsp_settings && array_key_exists( 'product_feed', $stsp_settings )) {
    10             $feed = $stsp_settings['product_feed'];
    11             if ( $feed && !wp_next_scheduled( 'stsp_product_feed_update' ) ) {
    12                 wp_schedule_event( time(), 'hourly', 'stsp_product_feed_update' );
    13             }
    14         } else {
     9        if( !$stsp_settings ) {
    1510            $options = [
    16                 'pixel_id' => '',
    17                 'product_feed' => 'no',
    18                 'product_category' => ''
     11                'pixel_id' => null,
     12                'pixel_enabled' => false,
     13                'feed_enabled' => false,
     14                'product_category' => 0,
    1915            ];
    20 
    2116            add_option( 'storespot_settings', $options );
     17            add_option( 'storespot_feed', null );
    2218        }
    2319
  • storespot/trunk/includes/class-storespot-deactivator.php

    r1977618 r2042059  
    22class StoreSpot_Deactivator {
    33    public static function deactivate() {
    4         wp_clear_scheduled_hook( 'stsp_product_feed_update' );
    54        delete_option( 'storespot_settings' );
     5        delete_option( 'storespot_feed' );
    66    }
    77}
  • storespot/trunk/includes/class-storespot.php

    r1977618 r2042059  
    2222            $this->version = STORESPOT_VERSION;
    2323        } else {
    24             $this->version = '1.0.0';
     24            $this->version = '0.0.0';
    2525        }
    2626        $this->plugin_name = 'storespot';
     
    4646        require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/class-storespot-messages.php';
    4747        require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/class-storespot-api.php';
     48        require_once plugin_dir_path( dirname( __FILE__ ) ) . 'admin/class-storespot-async.php';
    4849        require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-storespot-events.php';
    4950        require_once plugin_dir_path( dirname( __FILE__ ) ) . 'public/class-storespot-facebook-pixel.php';
     
    5556            ! class_exists( 'StoreSpot_API' ) ||
    5657            ! class_exists( 'StoreSpot_Events' ) ||
    57             ! class_exists( 'StoreSpot_Facebook_Pixel' )
     58            ! class_exists( 'StoreSpot_Facebook_Pixel' ) ||
     59            ! class_exists( 'StoreSpot_Async' )
    5860        ) {
    5961            return false;
     
    6567
    6668    private function define_admin_hooks() {
    67             $product_feed = new StoreSpot_Product_Feed();
    6869            $admin_message = new StoreSpot_Messages();
    69             $this->loader->add_action( 'stsp_product_feed_update', $product_feed, 'write_product_feed' );
     70            $async_request = new StoreSpot_Async();
     71            $products_feed = new StoreSpot_Product_Feed();
    7072            $this->loader->add_action( 'admin_notices', $admin_message, 'activation_notice' );
     73            $this->loader->add_action( 'wp_ajax_' . $async_request->get_ajax_action(), $async_request, 'execute' );
     74            $this->loader->add_action( 'wp_ajax_nopriv_' . $async_request->get_ajax_action(), $async_request, 'execute' );
     75            $this->loader->add_action( 'stsp_call_async_feed_update', $async_request, 'call' );
     76            $this->loader->add_action( $async_request->get_feed_action(), $products_feed, 'write_product_feed' );
    7177    }
    7278
     
    7480        $plugin_public = new StoreSpot_Events( $this->get_plugin_name(), $this->get_version() );
    7581        $pixel_id = $plugin_public->facebook_pixel->get_pixel_id();
    76         if( $pixel_id && ! $this->fb_integration_installed( $pixel_id ) ) {
     82        if( $pixel_id ) {
    7783            $this->loader->add_action( 'wp_head', $plugin_public, 'render_facebook_pixel' );
    78             $this->loader->add_action( 'wp_head', $plugin_public, 'render_facebook_pixel_noscript' );
     84            $this->loader->add_action( 'wp_footer', $plugin_public, 'render_facebook_pixel_noscript' );
    7985            $this->loader->add_action( 'woocommerce_after_single_product', $plugin_public, 'render_product_view_event');
    8086            $this->loader->add_action( 'woocommerce_after_shop_loop', $plugin_public, 'render_category_view_event');
     
    8490            $this->loader->add_action( 'woocommerce_after_checkout_form', $plugin_public, 'render_initiate_checkout_event' );
    8591            $this->loader->add_action( 'woocommerce_thankyou', $plugin_public, 'render_purchase_event' );
     92            $this->loader->add_action( 'woocommerce_payment_complete', $plugin_public, 'render_purchase_event' );
    8693            $this->loader->add_action( 'wp_footer', $plugin_public, 'custom_jquery_add_to_cart_script' );
    87             $this->loader->add_action( 'wc_ajax_render_add_to_cart_event', $plugin_public, 'render_ajax_add_to_cart_event' );
     94            $this->loader->add_action( 'wc_ajax_stsp_add_to_cart_event', $plugin_public, 'render_ajax_add_to_cart_event' );
    8895        }
    8996    }
    9097
    91     private function fb_integration_installed($pixel_id) {
    92         $fb_option = get_option('facebook_config');
    93         $fb_integration_option_set = false;
    94         if ( $fb_option && array_key_exists( 'pixel_id', $fb_option ) ) {
    95             if ( $fb_option['pixel_id'] == $pixel_id) {
    96                 $fb_integration_option_set = true;
    97             }
    98         }
    99         include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
    100         $fb_integration_activated = class_exists('WC_Facebookcommerce');
    101         return $fb_integration_activated && $fb_integration_option_set;
    102     }
    103 
    10498    private function define_api_hooks() {
    105             $api = new StoreSpot_API();
    106             $this->loader->add_action( 'rest_api_init', $api, 'storespot_api_route');
     99        $api = new StoreSpot_API();
     100        $this->loader->add_action( 'rest_api_init', $api, 'storespot_api_route');
    107101    }
    108102
  • storespot/trunk/public/class-storespot-events.php

    r1982419 r2042059  
    1818    public function get_facebook_content_id($product) {
    1919        $product_id = $product->get_id();
    20         $product_sku = $product->get_sku();
    21         $sku_id = $product_sku . '_' . $product_id;
    22         $other_id = 'wc_post_id_' . $product_id;
    23 
    24         $ids = array($other_id, $product_id);
    25         if ( $product_sku ) {
    26             $ids[] = $sku_id;
    27             $ids[] = $product_sku;
    28         }
    29 
    30         return $ids;
     20        return 'stsp_' . $product->get_id();
    3121    }
    3222
     
    3424        global $post;
    3525        $product = wc_get_product($post->ID);
     26        $content_type = 'product';
    3627
    3728        if ( $product ) {
     29            if( $product->get_type() == 'variable' ) {
     30                $content_type = 'product_group';
     31            }
    3832            $params = array();
     33            $params['content_ids'] = json_encode( [$this->get_facebook_content_id( $product )] );
     34            $params['content_type'] = $content_type;
     35            $params['content_name'] = $product->get_title();
     36            $params['currency'] = get_woocommerce_currency();
    3937            $params['value'] = $product->get_price();
    40             $params['content_name'] = $product->get_title();
    41             $params['content_type'] = ($product->get_type() == 'variable' ? 'product_group' : 'product');
    42             $params['currency'] = get_woocommerce_currency();
    43             $params['content_ids'] = json_encode( $this->get_facebook_content_id( $product ) );
    4438
    4539            $this->facebook_pixel->event_code( 'ViewContent', $params );
     
    5347
    5448        $products = array_values(array_map(function($item) {
    55         return wc_get_product($item->ID);
    56     }, $wp_query->posts));
     49            return wc_get_product($item->ID);
     50        }, $wp_query->posts));
    5751
    5852        $content_type = 'product';
     
    6054        foreach ($products as $product) {
    6155            if (!$product) { continue; }
    62             $product_ids = array_merge(
    63                 $product_ids,
    64                 $this->get_facebook_content_id($product)
    65             );
    66             if ($product->get_type() == 'variable') {
    67                 $content_type = 'product_group';
    68             }
    69     }
    70 
    71     $category_path = wp_get_post_terms( get_the_ID(), 'product_cat' );
     56            if ( $product->get_type() == 'variable' ) { continue; }
     57            $product_ids[] = $this->get_facebook_content_id($product);
     58        }
     59
     60        $category_path = wp_get_post_terms( get_the_ID(), 'product_cat' );
    7261        $content_category = array_values( array_map( function($item) {
    7362            return $item->name;
     
    8170
    8271        $params = array(
    83             'content_name'          => json_encode($categories['name']),
     72            'content_name'      => json_encode($categories['name']),
    8473            'content_category'  => json_encode($categories['categories']),
    85             'content_ids'           => json_encode(array_slice($product_ids, 0, 10)),
    86             'content_type'          => $content_type
     74            'content_ids'       => json_encode($product_ids),
     75            'content_type'      => $content_type
    8776        );
    8877
     
    112101        $product_ids = array();
    113102        foreach ( $products as $item ) {
    114             $product_ids = array_merge(
    115         $product_ids,
    116         $this->get_facebook_content_id( $item['data'] )
    117             );
     103            $product_ids[] = $this->get_facebook_content_id( $item['data'] );
    118104        }
    119105
     
    134120
    135121    public function render_ajax_add_to_cart_event() {
     122
    136123        global $woocommerce;
    137124        $products = $woocommerce->cart->get_cart();
     125
     126        ob_start();
     127
    138128        $product_ids = array();
    139129        foreach ( $products as $item ) {
    140             $product_ids = array_merge(
    141         $product_ids,
    142         $this->get_facebook_content_id( $item['data'] )
    143             );
    144         }
     130            $product_ids[] = $this->get_facebook_content_id( $item['data'] );
     131        }
     132
    145133        $params = array();
    146134        $params['content_ids'] = json_encode( $product_ids );
     
    149137        $params['currency'] = get_woocommerce_currency();
    150138
    151         $code = $this->facebook_pixel->ajax_event_code( 'AddToCart', $params );
    152         wp_send_json($code);
     139        echo $this->facebook_pixel->ajax_event_code( 'AddToCart', $params );
     140
     141        $pixel = ob_get_clean();
     142        wp_send_json($pixel);
    153143    }
    154144
     
    162152        $product_ids = array();
    163153        foreach ( $products as $item ) {
    164             $product_ids = array_merge(
    165         $product_ids,
    166         $this->get_facebook_content_id( $item['data'] )
    167             );
     154            $product_id[] = $this->get_facebook_content_id( $item['data'] );
    168155        }
    169156
     
    184171
    185172        $order = wc_get_order( $order_id );
     173        $content_type = 'product';
    186174        $product_ids = array();
    187175        foreach ( $order->get_items() as $item ) {
    188176            $product = $item->get_product();
    189             $product_ids = array_merge(
    190         $product_ids,
    191         $this->get_facebook_content_id( $product )
    192             );
    193         }
    194 
    195         $params = array();
    196         $params['content_ids'] = json_encode( $product_ids );
    197         $params['content_type'] = 'product';
     177            $product_ids[] = $this->get_facebook_content_id( $product );
     178            if( $product->get_type() == 'variable' ) {
     179                $content_type = 'product_group';
     180            }
     181        }
     182
     183        $params = array();
     184        $params['content_ids'] = json_encode( $product_ids );
     185        $params['content_type'] = $content_type;
    198186        $params['value'] = $order->get_total();
    199187        $params['currency'] = get_woocommerce_currency();
     
    203191
    204192    public function custom_jquery_add_to_cart_script(){
    205         if ( is_shop() || is_product_category() || is_product_tag() ):
    206         ?>
    207             <script type="text/javascript">
    208                 (function($){
    209                     $( document.body ).on( 'added_to_cart', function(){
    210                         $.get('?wc-ajax=render_add_to_cart_event', function(script) {
    211                             console.log(script);
    212                             $('head').append(script);
    213                         });
    214                     });
    215                 })(jQuery);
    216             </script>
    217             <?php
    218         endif;
     193        if ( is_front_page() || is_shop() || is_product_category() || is_product_tag() ) {
     194
     195            echo "
     196<!-- StoreSpot Facebook Listener Begin -->
     197<script type='text/javascript'>
     198document.addEventListener('DOMContentLoaded', function() {
     199  jQuery && jQuery(function($){
     200    $('body').on('added_to_cart', function(event) {
     201      // Ajax action.
     202      $.get('?wc-ajax=stsp_add_to_cart_event', function(data) {
     203        $('head').append(data);
     204      });
     205    });
     206  });
     207}, false);
     208</script>
     209<!-- StoreSpot Facebook Listener End -->
     210            ";
     211
     212        }
    219213    }
    220214}
  • storespot/trunk/public/class-storespot-facebook-pixel.php

    r1969706 r2042059  
    4040    public function get_pixel_id() {
    4141        $stsp_settings = get_option( 'storespot_settings' );
    42         if( $stsp_settings && array_key_exists( 'pixel_id', $stsp_settings )) {
     42        if(
     43            $stsp_settings
     44            && array_key_exists( 'pixel_id', $stsp_settings )
     45            && array_key_exists( 'pixel_enabled', $stsp_settings )
     46            && $stsp_settings['pixel_enabled'] === true
     47            && $stsp_settings['pixel_id'] !== null
     48        ) {
    4349            return $stsp_settings['pixel_id'];
    4450        }
  • storespot/trunk/readme.txt

    r1982419 r2042059  
    33Tags: woocommerce, facebook, dynamic ads, retargeting, woocommerce marketing, remarketing
    44Requires at least: 4.4.0
    5 Tested up to: 4.9
     5Tested up to: 5.1
    66Requires PHP: 5.6
    7 Stable tag: 1.0.10
     7Stable tag: 1.1.0
    88License: GPLv2 or later
    99License URI: http://www.gnu.org/licenses/gpl-2.0.html
     
    5050== Changelog ==
    5151
    52 = 1.0.10 =
    53 * Bug fixes for add to cart events and purchase events
    54 * Support for combined category events
     52= 1.1.0 =
     53* Fix add-to-cart events with ajax
     54* Improved product and category matching
     55* Improved memory usage in feed generation
    5556
    56 = 1.0.9 =
    57 * Add category view to pixel data
    58 * Remove options after plugin deactivation
    59 
    60 = 1.0.8 =
    61 * Improve memory usage in feed generation
    62 
    63 = 1.0.7 =
    64 * Compatibility with Facebook for WooCommerce plugin
    65 
    66 = 1.0.6 =
    67 * Use pagination on feed generation
    68 
    69 = 1.0.5 =
    70 * Add registration button to welcome message
    71 * Add error handling and default fields in product feed
    72 
    73 = 1.0.4 =
    74 * Fix product feed encoding
    75 * Add brand names to feed
    76 
    77 = 1.0.3 =
    78 * Extended admin notices
    79 * Add integration with official Facebook plugin
    80 
    81 = 1.0.2 =
    82 * Upgrade WooCommerce REST API to v2
    83 
    84 = 1.0.1 =
    85 * Update description.
    86 * Add plugin banner.
    87 * Rename plugin.
    88 
    89 = 1.0.0 =
    90 * Initial release.
     57= 1.0 =
     58* Beta release
  • storespot/trunk/storespot.php

    r1982419 r2042059  
    44 * Plugin URI:   https://storespot.io/
    55 * Description:  Stop leaving money on the table. Automate your retargeting ads with StoreSpot.
    6  * Version:      1.0.10
     6 * Version:      1.1.0
    77 * Author:       StoreSpot
    88**/
     
    1111if ( ! defined( 'WPINC' ) ) { die; }
    1212
    13 define( 'STORESPOT_VERSION', '1.0.10' );
     13define( 'STORESPOT_VERSION', '1.1.0' );
    1414
    1515function activate_storespot() {
Note: See TracChangeset for help on using the changeset viewer.