Version Notes
Plugin corresponds to version 6.0.2 of the Bazaarvoice platform
Download this release
Release Info
Developer | BV DTS |
Extension | Bazaarvoice_Connector |
Version | 6.0.3 |
Comparing to | |
See all releases |
Version 6.0.3
- app/code/local/Bazaarvoice/Connector/Block/Bazaarvoice.php +24 -0
- app/code/local/Bazaarvoice/Connector/Block/Ratings.php +37 -0
- app/code/local/Bazaarvoice/Connector/Block/Reviews.php +63 -0
- app/code/local/Bazaarvoice/Connector/Block/Roi/Beacon.php +77 -0
- app/code/local/Bazaarvoice/Connector/Block/Submissioncontainer.php +18 -0
- app/code/local/Bazaarvoice/Connector/Helper/Data.php +484 -0
- app/code/local/Bazaarvoice/Connector/Model/ExportProductFeed.php +386 -0
- app/code/local/Bazaarvoice/Connector/Model/ExportPurchaseFeed.php +639 -0
- app/code/local/Bazaarvoice/Connector/Model/Mysql4/Setup.php +11 -0
- app/code/local/Bazaarvoice/Connector/Model/ProductFeed/Brand.php +191 -0
- app/code/local/Bazaarvoice/Connector/Model/ProductFeed/Category.php +301 -0
- app/code/local/Bazaarvoice/Connector/Model/ProductFeed/Product.php +333 -0
- app/code/local/Bazaarvoice/Connector/Model/RetrieveInlineRatingsFeed.php +219 -0
- app/code/local/Bazaarvoice/Connector/Model/RetrieveSmartSEOPackage.php +143 -0
- app/code/local/Bazaarvoice/Connector/Model/Source/AuthenticationMethod.php +25 -0
- app/code/local/Bazaarvoice/Connector/Model/Source/Environment.php +18 -0
- app/code/local/Bazaarvoice/Connector/Model/Source/FeedGenerationScope.php +30 -0
- app/code/local/Bazaarvoice/Connector/Model/Source/TriggeringEvent.php +25 -0
- app/code/local/Bazaarvoice/Connector/controllers/FeedController.php +50 -0
- app/code/local/Bazaarvoice/Connector/controllers/IndexController.php +25 -0
- app/code/local/Bazaarvoice/Connector/etc/adminhtml.xml +25 -0
- app/code/local/Bazaarvoice/Connector/etc/config.xml +159 -0
- app/code/local/Bazaarvoice/Connector/etc/system.xml +300 -0
- app/code/local/Bazaarvoice/Connector/sql/bazaarvoice_setup/mysql4-install-0.1.0.php +16 -0
- app/design/frontend/enterprise/default/layout/bazaarvoice.xml +131 -0
- app/design/frontend/enterprise/default/template/bazaarvoice/display/headerincludes.phtml +4 -0
- app/design/frontend/enterprise/default/template/bazaarvoice/display/headerproduct.phtml +30 -0
- app/design/frontend/enterprise/default/template/bazaarvoice/display/qa/questions.phtml +15 -0
- app/design/frontend/enterprise/default/template/bazaarvoice/display/qa/questionsummary.phtml +5 -0
- app/design/frontend/enterprise/default/template/bazaarvoice/display/rr/ratings.phtml +15 -0
- app/design/frontend/enterprise/default/template/bazaarvoice/display/rr/reviews.phtml +16 -0
- app/design/frontend/enterprise/default/template/bazaarvoice/display/rr/reviewsummary.phtml +5 -0
- app/design/frontend/enterprise/default/template/bazaarvoice/submit/roi_beacon.phtml +5 -0
- app/design/frontend/enterprise/default/template/bazaarvoice/submit/submissioncontainer.phtml +5 -0
- app/etc/modules/Bazaarvoice_Connector.xml +9 -0
- app/locale/en_US/template/email/bazaarvoice_notification.html +5 -0
- lib/Bazaarvoice/bvseosdk.php +511 -0
- package.xml +18 -0
- shell/bv_export_order_feed.php +38 -0
- shell/bv_export_product_feed.php +38 -0
- skin/frontend/base/default/images/bazaarvoice/rating-0_0.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-1_0.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-1_1.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-1_2.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-1_3.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-1_4.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-1_5.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-1_6.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-1_7.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-1_8.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-1_9.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-2_0.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-2_1.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-2_2.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-2_3.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-2_4.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-2_5.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-2_6.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-2_7.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-2_8.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-2_9.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-3_0.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-3_1.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-3_2.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-3_3.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-3_4.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-3_5.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-3_6.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-3_7.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-3_8.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-3_9.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-4_0.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-4_1.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-4_2.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-4_3.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-4_4.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-4_5.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-4_6.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-4_7.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-4_8.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-4_9.gif +0 -0
- skin/frontend/base/default/images/bazaarvoice/rating-5_0.gif +0 -0
app/code/local/Bazaarvoice/Connector/Block/Bazaarvoice.php
ADDED
@@ -0,0 +1,24 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
class Bazaarvoice_Connector_Block_Bazaarvoice extends Mage_Core_Block_Template
|
3 |
+
{
|
4 |
+
|
5 |
+
/**
|
6 |
+
* NOTE: This class isn't used by the current Bazaarvoice integration, but is left
|
7 |
+
* here as a placeholder for future integration.
|
8 |
+
*/
|
9 |
+
|
10 |
+
|
11 |
+
public function _prepareLayout()
|
12 |
+
{
|
13 |
+
return parent::_prepareLayout();
|
14 |
+
}
|
15 |
+
|
16 |
+
public function getRatingsandreviews()
|
17 |
+
{
|
18 |
+
if (!$this->hasData('ratingsandreviews')) {
|
19 |
+
$this->setData('ratingsandreviews', Mage::registry('ratingsandreviews'));
|
20 |
+
}
|
21 |
+
return $this->getData('ratingsandreviews');
|
22 |
+
}
|
23 |
+
|
24 |
+
}
|
app/code/local/Bazaarvoice/Connector/Block/Ratings.php
ADDED
@@ -0,0 +1,37 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
class Bazaarvoice_Connector_Block_Ratings extends Mage_Core_Block_Template
|
3 |
+
{
|
4 |
+
|
5 |
+
private $_isEnabled;
|
6 |
+
|
7 |
+
public function _construct()
|
8 |
+
{
|
9 |
+
// enabled/disabled in admin
|
10 |
+
$this->_isEnabled = Mage::getStoreConfig('bazaarvoice/rr/enable_inline_ratings') === '1'
|
11 |
+
&& Mage::getStoreConfig('bazaarvoice/rr/enable_rr') === '1'
|
12 |
+
&& Mage::getStoreConfig('bazaarvoice/general/enable_bv') === '1';
|
13 |
+
}
|
14 |
+
|
15 |
+
/**
|
16 |
+
* returns true if feature is enabled in admin, otherwise returns false
|
17 |
+
* @return bool
|
18 |
+
*/
|
19 |
+
public function getIsEnabled()
|
20 |
+
{
|
21 |
+
return $this->_isEnabled;
|
22 |
+
}
|
23 |
+
|
24 |
+
public function getLoadedProductCollection()
|
25 |
+
{
|
26 |
+
// Get reference to parent block - product list
|
27 |
+
$productListBlock = $this->getParentBlock();
|
28 |
+
// Verify the parent is really a product list
|
29 |
+
if(!($productListBlock instanceof Mage_Catalog_Block_Product_List)) {
|
30 |
+
// Return empty array to keep template code happy
|
31 |
+
return array();
|
32 |
+
}
|
33 |
+
// Get and return ref to loaded prod collection
|
34 |
+
return $productListBlock->getLoadedProductCollection();
|
35 |
+
}
|
36 |
+
|
37 |
+
}
|
app/code/local/Bazaarvoice/Connector/Block/Reviews.php
ADDED
@@ -0,0 +1,63 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
|
3 |
+
include 'Bazaarvoice/bvseosdk.php';
|
4 |
+
|
5 |
+
class Bazaarvoice_Connector_Block_Reviews extends Mage_Core_Block_Template
|
6 |
+
{
|
7 |
+
|
8 |
+
private $_isEnabled;
|
9 |
+
|
10 |
+
public function _construct()
|
11 |
+
{
|
12 |
+
// enabled/disabled in admin
|
13 |
+
$this->_isEnabled = Mage::getStoreConfig('bazaarvoice/rr/enable_rr') === '1'
|
14 |
+
&& Mage::getStoreConfig('bazaarvoice/general/enable_bv') === '1';
|
15 |
+
}
|
16 |
+
|
17 |
+
/**
|
18 |
+
* returns true if feature is enabled in admin, otherwise returns false
|
19 |
+
* @return bool
|
20 |
+
*/
|
21 |
+
public function getIsEnabled()
|
22 |
+
{
|
23 |
+
return $this->_isEnabled;
|
24 |
+
}
|
25 |
+
|
26 |
+
public function getSEOContent()
|
27 |
+
{
|
28 |
+
$seoContent = '';
|
29 |
+
if(Mage::getStoreConfig('bazaarvoice/general/enable_cloud_seo') === '1' && $this->getIsEnabled()) {
|
30 |
+
// Check if admin has configured a legacy display code
|
31 |
+
if(strlen(Mage::getStoreConfig('bazaarvoice/bv_config/display_code'))) {
|
32 |
+
$deploymentZoneId =
|
33 |
+
Mage::getStoreConfig('bazaarvoice/bv_config/display_code') .
|
34 |
+
'-' . Mage::getStoreConfig('bazaarvoice/general/locale');
|
35 |
+
}
|
36 |
+
else {
|
37 |
+
$deploymentZoneId =
|
38 |
+
str_replace(' ', '_', Mage::getStoreConfig('bazaarvoice/general/deployment_zone')) .
|
39 |
+
'-' . Mage::getStoreConfig('bazaarvoice/general/locale');
|
40 |
+
}
|
41 |
+
$bv = new BV(array(
|
42 |
+
'deployment_zone_id' => $deploymentZoneId, // replace with your display code (BV provided)
|
43 |
+
'product_id' => Mage::helper('bazaarvoice')->getProductId(Mage::registry('current_product')), // replace with product id
|
44 |
+
'cloud_key' => Mage::getStoreConfig('bazaarvoice/general/cloud_seo_key'), // BV provided value
|
45 |
+
'staging' => TRUE
|
46 |
+
));
|
47 |
+
$seoContent = $bv->reviews->renderSeo();
|
48 |
+
}
|
49 |
+
|
50 |
+
return $seoContent;
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Retrieve block cache tags based on category
|
55 |
+
*
|
56 |
+
* @return array
|
57 |
+
*/
|
58 |
+
public function getCacheTags()
|
59 |
+
{
|
60 |
+
return array_merge(parent::getCacheTags(), Mage::registry('current_product')->getCacheIdTags());
|
61 |
+
}
|
62 |
+
|
63 |
+
}
|
app/code/local/Bazaarvoice/Connector/Block/Roi/Beacon.php
ADDED
@@ -0,0 +1,77 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
class Bazaarvoice_Connector_Block_Roi_Beacon extends Mage_Core_Block_Template
|
3 |
+
{
|
4 |
+
private $_isEnabled;
|
5 |
+
|
6 |
+
public function _construct()
|
7 |
+
{
|
8 |
+
// enabled/disabled in admin
|
9 |
+
$this->_isEnabled = Mage::getStoreConfig('bazaarvoice/general/enable_roibeacon') === '1'
|
10 |
+
&& Mage::getStoreConfig('bazaarvoice/general/enable_bv') === '1';
|
11 |
+
}
|
12 |
+
|
13 |
+
/**
|
14 |
+
* returns true if feature is enabled in admin, otherwise returns false
|
15 |
+
* @return bool
|
16 |
+
*/
|
17 |
+
public function getIsEnabled()
|
18 |
+
{
|
19 |
+
return $this->_isEnabled;
|
20 |
+
}
|
21 |
+
|
22 |
+
/**
|
23 |
+
* returns serialized order details data for transmission to Bazaarvoice
|
24 |
+
* @return string
|
25 |
+
*/
|
26 |
+
public function getOrderDetails()
|
27 |
+
{
|
28 |
+
$orderDetails = array();
|
29 |
+
$orderId = Mage::getSingleton('checkout/session')->getLastOrderId();
|
30 |
+
if ($orderId)
|
31 |
+
{
|
32 |
+
$order = Mage::getModel('sales/order')->load($orderId);
|
33 |
+
if ($order->getId())
|
34 |
+
{
|
35 |
+
$address = $order->getBillingAddress();
|
36 |
+
|
37 |
+
$orderDetails['orderId'] = $order->getId();
|
38 |
+
$orderDetails['tax'] = number_format($order->getTaxAmount(), 2, '.', '');
|
39 |
+
$orderDetails['shipping'] = number_format($order->getShippingAmount(), 2, '.', '');
|
40 |
+
$orderDetails['total'] = number_format($order->getGrandTotal(), 2, '.', '');
|
41 |
+
$orderDetails['city'] = $address->getCity();
|
42 |
+
$orderDetails['state'] = Mage::getModel('directory/region')->load($address->getRegionId())->getCode();
|
43 |
+
$orderDetails['country'] = $address->getCountryId();
|
44 |
+
$orderDetails['currency'] = $order->getOrderCurrencyCode();
|
45 |
+
|
46 |
+
$orderDetails['items'] = array();
|
47 |
+
$items = $order->getAllVisibleItems();
|
48 |
+
foreach ($items as $itemId => $item)
|
49 |
+
{
|
50 |
+
$product = Mage::helper('bazaarvoice')->getReviewableProductFromOrderItem($item);
|
51 |
+
|
52 |
+
$itemDetails = array();
|
53 |
+
$itemDetails['sku'] = Mage::helper('bazaarvoice')->getProductId($product);
|
54 |
+
$itemDetails['name'] = $item->getName();
|
55 |
+
// 'category' is not included. Mage products can be in 0 - many categories. Should we try to include it?
|
56 |
+
$itemDetails['price'] = number_format($item->getPrice(), 2, '.', '');
|
57 |
+
$itemDetails['quantity'] = number_format($item->getQtyOrdered(), 0);
|
58 |
+
$itemDetails['imageUrl'] = $product->getImageUrl();
|
59 |
+
|
60 |
+
array_push($orderDetails['items'], $itemDetails);
|
61 |
+
}
|
62 |
+
|
63 |
+
$orderDetails['userId'] = $order->getCustomerId();
|
64 |
+
$orderDetails['email'] = $order->getCustomerEmail();
|
65 |
+
$orderDetails['nickname'] = $order->getCustomerEmail();
|
66 |
+
// There is no 'deliveryDate' yet
|
67 |
+
$orderDetails['locale'] = Mage::getStoreConfig('bazaarvoice/general/locale', $order->getStoreId());
|
68 |
+
|
69 |
+
// Add partnerSource field
|
70 |
+
$orderDetails['partnerSource'] = 'Magento Extension r' . Mage::helper('bazaarvoice')->getExtensionVersion();
|
71 |
+
}
|
72 |
+
}
|
73 |
+
|
74 |
+
$orderDetailsJson = Mage::helper('core')->jsonEncode($orderDetails);
|
75 |
+
return urldecode(stripslashes($orderDetailsJson));
|
76 |
+
}
|
77 |
+
}
|
app/code/local/Bazaarvoice/Connector/Block/Submissioncontainer.php
ADDED
@@ -0,0 +1,18 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
class Bazaarvoice_Connector_Block_Submissioncontainer extends Mage_Core_Block_Template
|
3 |
+
{
|
4 |
+
|
5 |
+
public function _prepareLayout()
|
6 |
+
{
|
7 |
+
parent::_prepareLayout();
|
8 |
+
|
9 |
+
if ($headBlock = $this->getLayout()->getBlock('head')) {
|
10 |
+
$headBlock->addLinkRel('canonical', $this->getUrl('bazaarvoice'));
|
11 |
+
}
|
12 |
+
|
13 |
+
return $this;
|
14 |
+
}
|
15 |
+
|
16 |
+
|
17 |
+
|
18 |
+
}
|
app/code/local/Bazaarvoice/Connector/Helper/Data.php
ADDED
@@ -0,0 +1,484 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Bazaarvoice_Connector_Helper_Data extends Mage_Core_Helper_Abstract
|
4 |
+
{
|
5 |
+
|
6 |
+
const BV_SUBJECT_TYPE = 'bvSubjectType';
|
7 |
+
const BV_EXTERNAL_SUBJECT_NAME = 'bvExternalSubjectName';
|
8 |
+
const BV_EXTERNAL_SUBJECT_ID = 'bvExternalSubjectID';
|
9 |
+
|
10 |
+
const CONST_SMARTSEO_BVRRP = 'bvrrp';
|
11 |
+
const CONST_SMARTSEO_BVQAP = 'bvqap';
|
12 |
+
const CONST_SMARTSEO_BVSYP = 'bvsyp';
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Get the uniquely identifying product ID for a catalog product.
|
16 |
+
*
|
17 |
+
* This is the unique, product family-level id (duplicates are unacceptable).
|
18 |
+
* If a product has its own page, this is its product ID. It is not necessarily
|
19 |
+
* the SKU ID, as we do not collect separate Ratings & Reviews for different
|
20 |
+
* styles of product - i.e. the 'Blue' vs. 'Red Widget'.
|
21 |
+
*
|
22 |
+
* @static
|
23 |
+
* @param $product a reference to a catalog product object
|
24 |
+
* @return The unique product ID to be used with Bazaarvoice
|
25 |
+
*/
|
26 |
+
public function getProductId($product)
|
27 |
+
{
|
28 |
+
$rawProductId = $product->getSku();
|
29 |
+
|
30 |
+
// >> Customizations go here
|
31 |
+
//
|
32 |
+
// << No further customizations after this
|
33 |
+
|
34 |
+
return $this->replaceIllegalCharacters($rawProductId);
|
35 |
+
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Returns a product object that has the provided external ID. This is a complementary
|
40 |
+
* function to getProductId above.
|
41 |
+
*
|
42 |
+
* @static
|
43 |
+
* @param $productExternalId
|
44 |
+
* @return product object for the provided external ID, or null if no match is found.
|
45 |
+
*/
|
46 |
+
public function getProductFromProductExternalId($productExternalId)
|
47 |
+
{
|
48 |
+
$rawId = $this->reconstructRawId($productExternalId);
|
49 |
+
|
50 |
+
$model = Mage::getModel('catalog/product');
|
51 |
+
|
52 |
+
$productCollection = $model->getCollection()->addAttributeToSelect('*')
|
53 |
+
->addAttributeToFilter('sku', $rawId)
|
54 |
+
->load();
|
55 |
+
|
56 |
+
|
57 |
+
foreach ($productCollection as $product) {
|
58 |
+
// return the first one
|
59 |
+
return $product;
|
60 |
+
}
|
61 |
+
|
62 |
+
return null;
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Get the uniquely identifying category ID for a catalog category.
|
67 |
+
*
|
68 |
+
* This is the unique, category or subcategory ID (duplicates are unacceptable).
|
69 |
+
* This ID should be stable: it should not change for the same logical category even
|
70 |
+
* if the category's name changes.
|
71 |
+
*
|
72 |
+
* @static
|
73 |
+
* @param $category a reference to a catalog category object
|
74 |
+
* @return The unique category ID to be used with Bazaarvoice
|
75 |
+
*/
|
76 |
+
public function getCategoryId($category, $storeId = null)
|
77 |
+
{
|
78 |
+
// Check config setting to see if we should use Magento category id
|
79 |
+
$useUrlPath = Mage::getStoreConfig('bazaarvoice/bv_config/category_id_use_url_path', $storeId);
|
80 |
+
$useUrlPath = (strtoupper($useUrlPath) == 'TRUE' || $useUrlPath == true || $useUrlPath == '1');
|
81 |
+
if(!$useUrlPath) {
|
82 |
+
return $category->getId();
|
83 |
+
}
|
84 |
+
else {
|
85 |
+
// Generate a unique id based on category path
|
86 |
+
// Start with url path
|
87 |
+
$rawCategoryId = $category->getUrlPath();
|
88 |
+
// Replace slashes with dashes in url path
|
89 |
+
$rawCategoryId = str_replace('/', '-', $rawCategoryId);
|
90 |
+
// Replace any illegal characters
|
91 |
+
return $this->replaceIllegalCharacters($rawCategoryId);
|
92 |
+
}
|
93 |
+
}
|
94 |
+
|
95 |
+
public function getBrandId($product)
|
96 |
+
{
|
97 |
+
// Get brand
|
98 |
+
$brand = $product->getData('brand');
|
99 |
+
// Replace any illegal characters
|
100 |
+
$brandId = $this->replaceIllegalCharacters($brand);
|
101 |
+
|
102 |
+
return $brandId;
|
103 |
+
}
|
104 |
+
|
105 |
+
/**
|
106 |
+
* This unique ID can only contain alphanumeric characters (letters and numbers
|
107 |
+
* only) and also the asterisk, hyphen, period, and underscore characters. If your
|
108 |
+
* product IDs contain invalid characters, simply replace them with an alternate
|
109 |
+
* character like an underscore. This will only be used in the feed and not for
|
110 |
+
* any customer facing purpose.
|
111 |
+
*
|
112 |
+
* @static
|
113 |
+
* @param $rawId
|
114 |
+
* @return mixed
|
115 |
+
*/
|
116 |
+
public function replaceIllegalCharacters($rawId)
|
117 |
+
{
|
118 |
+
// We need to use a reversible replacement so that we can reconstruct the original ID later.
|
119 |
+
// Example rawId = qwerty$%@#asdf
|
120 |
+
// Example encoded = qwerty_bv36__bv37__bv64__bv35_asdf
|
121 |
+
|
122 |
+
return preg_replace_callback('/[^\w\d\*-\._]/s', create_function('$match','return "_bv".ord($match[0])."_";'), $rawId);
|
123 |
+
}
|
124 |
+
|
125 |
+
public function reconstructRawId($externalId) {
|
126 |
+
return preg_replace_callback('/_bv(\d*)_/s', create_function('$match','return chr($match[1]);'), $externalId);
|
127 |
+
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Connects to Bazaarvoice SFTP server and retrieves remote file to a local directory.
|
131 |
+
* Local directory will be created if it doesn't exist. Returns false if there
|
132 |
+
* are any problems downloading the file. Otherwise returns true.
|
133 |
+
*
|
134 |
+
* @static
|
135 |
+
* @param $localFilePath
|
136 |
+
* @param $localFileName
|
137 |
+
* @param $remoteFile
|
138 |
+
* @return boolean
|
139 |
+
*/
|
140 |
+
public function downloadFile($localFilePath, $localFileName, $remoteFile, $store = null)
|
141 |
+
{
|
142 |
+
Mage::log(' BV - starting download from Bazaarvoice server');
|
143 |
+
|
144 |
+
// Create the directory if it doesn't already exist.
|
145 |
+
$ioObject = new Varien_Io_File();
|
146 |
+
try {
|
147 |
+
if (!$ioObject->fileExists($localFilePath, false)) {
|
148 |
+
$ioObject->mkdir($localFilePath, 0777, true);
|
149 |
+
}
|
150 |
+
} catch (Exception $e) {
|
151 |
+
// Most likely not enough permissions.
|
152 |
+
Mage::log(" BV - failed attempting to create local directory '".$localFilePath."' to download feed. Error trace follows: " . $e->getTraceAsString());
|
153 |
+
return false;
|
154 |
+
}
|
155 |
+
|
156 |
+
// Make sure directory is writable
|
157 |
+
if (!$ioObject->isWriteable($localFilePath)) {
|
158 |
+
Mage::log(" BV - local directory '".$localFilePath."' is not writable.");
|
159 |
+
return false;
|
160 |
+
}
|
161 |
+
|
162 |
+
// Establish a connection to the FTP host
|
163 |
+
Mage::log(' BV - beginning file download');
|
164 |
+
$connection = ftp_connect($this->getSFTPHost());
|
165 |
+
$ftpUser = strtolower(Mage::getStoreConfig('bazaarvoice/general/client_name', $store));
|
166 |
+
$ftpPw = Mage::getStoreConfig('bazaarvoice/general/ftp_password', $store);
|
167 |
+
Mage::log('Connecting with ftp user: ' . $ftpUser);
|
168 |
+
Mage::log('Connecting with ftp pw: ' . $ftpPw);
|
169 |
+
$login = ftp_login($connection, $ftpUser, $ftpPw);
|
170 |
+
ftp_pasv($connection, true);
|
171 |
+
if (!$connection || !$login) {
|
172 |
+
Mage::log(' BV - FTP connection attempt failed!');
|
173 |
+
return false;
|
174 |
+
}
|
175 |
+
|
176 |
+
// Remove the local file if it already exists
|
177 |
+
if (file_exists($localFilePath . DS . $localFileName)) {
|
178 |
+
unlink($localFilePath . DS . $localFileName);
|
179 |
+
}
|
180 |
+
|
181 |
+
try {
|
182 |
+
// Download the file
|
183 |
+
ftp_get($connection, $localFilePath . DS . $localFileName, $remoteFile, FTP_BINARY);
|
184 |
+
} catch (Exception $ex) {
|
185 |
+
Mage::log(' BV - Exception downloading file: ' . $ex->getTraceAsString());
|
186 |
+
}
|
187 |
+
|
188 |
+
// Validate file was downloaded
|
189 |
+
if (!$ioObject->fileExists($localFilePath . DS . $localFileName, true)) {
|
190 |
+
Mage::log(" BV - unable to download file '" . $localFilePath . DS . $localFileName . "'");
|
191 |
+
return false;
|
192 |
+
}
|
193 |
+
|
194 |
+
return true;
|
195 |
+
}
|
196 |
+
|
197 |
+
|
198 |
+
public function uploadFile($localFileName, $remoteFile, $store)
|
199 |
+
{
|
200 |
+
Mage::log(' BV - starting upload to Bazaarvoice server');
|
201 |
+
|
202 |
+
$ftpUser = strtolower(Mage::getStoreConfig('bazaarvoice/general/client_name', $store->getId()));
|
203 |
+
$ftpPw = Mage::getStoreConfig('bazaarvoice/general/ftp_password', $store->getId());
|
204 |
+
Mage::log('Connecting with ftp user: ' . $ftpUser);
|
205 |
+
//Mage::log('Connecting with ftp pw: ' . $ftpPw);
|
206 |
+
|
207 |
+
$connection = ftp_connect($this->getSFTPHost($store));
|
208 |
+
if (!$connection) {
|
209 |
+
Mage::log(' BV - FTP connection attempt failed!');
|
210 |
+
return false;
|
211 |
+
}
|
212 |
+
$login = ftp_login($connection, $ftpUser, $ftpPw);
|
213 |
+
ftp_pasv($connection, true);
|
214 |
+
if (!$connection || !$login) {
|
215 |
+
Mage::log(' BV - FTP connection attempt failed!');
|
216 |
+
return false;
|
217 |
+
}
|
218 |
+
|
219 |
+
$upload = ftp_put($connection, $remoteFile, $localFileName, FTP_BINARY);
|
220 |
+
|
221 |
+
ftp_close($connection);
|
222 |
+
|
223 |
+
return $upload;
|
224 |
+
}
|
225 |
+
|
226 |
+
public function getSmartSEOContent($bvProduct, $bvSubjectArr, $pageFormat)
|
227 |
+
{
|
228 |
+
$ret = '';
|
229 |
+
|
230 |
+
if (Mage::getStoreConfig('bazaarvoice/SmartSEOFeed/EnableSmartSEO') === '1') {
|
231 |
+
$deploymentZone = $this->getDeploymentZoneForBVProduct($bvProduct);
|
232 |
+
if ($pageFormat != '') {
|
233 |
+
$pageFormat += '/';
|
234 |
+
}
|
235 |
+
|
236 |
+
$baseFolder = Mage::getBaseDir('var') . DS . 'import' . DS . 'bvfeeds' . DS . 'bvsmartseo' . DS;
|
237 |
+
$smartSEOFile = $baseFolder . $deploymentZone . DS . $bvProduct . DS . $bvSubjectArr[$this->BV_SUBJECT_TYPE] . DS . '1' . DS . $pageFormat . $bvSubjectArr[$this->BV_EXTERNAL_SUBJECT_ID] . '.htm';
|
238 |
+
|
239 |
+
if (isset($_REQUEST[$this->CONST_SMARTSEO_BVRRP])) {
|
240 |
+
$smartSEOFile = $baseFolder . $_REQUEST[$this->CONST_SMARTSEO_BVRRP];
|
241 |
+
} else if (isset($_REQUEST[$this->CONST_SMARTSEO_BVQAP])) {
|
242 |
+
$smartSEOFile = $baseFolder . $_REQUEST[$this->CONST_SMARTSEO_BVQAP];
|
243 |
+
} else if (isset($_REQUEST[$this->CONST_SMARTSEO_BVSYP])) {
|
244 |
+
$smartSEOFile = $baseFolder . $_REQUEST[$this->CONST_SMARTSEO_BVSYP];
|
245 |
+
}
|
246 |
+
|
247 |
+
if (file_exists($smartSEOFile)) {
|
248 |
+
$ret = file_get_contents($smartSEOFile);
|
249 |
+
}
|
250 |
+
|
251 |
+
if (!empty($ret)) {
|
252 |
+
$helper = Mage::helper('core/url');
|
253 |
+
$url = parse_url($helper->getCurrentUrl());
|
254 |
+
|
255 |
+
$query = array();
|
256 |
+
if (isset($_SERVER['QUERY_STRING']) && $_SERVER['QUERY_STRING'] != '') {
|
257 |
+
foreach ($_GET as $key => $value) {
|
258 |
+
if ($key !== $this->CONST_SMARTSEO_BVRRP && $key !== $this->CONST_SMARTSEO_BVQAP && $key !== $this->CONST_SMARTSEO_BVSYP) {
|
259 |
+
$query[$helper->stripTags($key, null, true)] = $helper->stripTags($value, null, true);
|
260 |
+
}
|
261 |
+
}
|
262 |
+
$url['query'] = http_build_query($query);
|
263 |
+
}
|
264 |
+
|
265 |
+
$currentPage = $url['scheme'] . '://' . $url['host'] . $url['path'] . '?' . $url['query'];
|
266 |
+
$ret = preg_replace("/\\{INSERT_PAGE_URI\\}/", $currentPage, $ret);
|
267 |
+
}
|
268 |
+
}
|
269 |
+
|
270 |
+
return $ret;
|
271 |
+
}
|
272 |
+
|
273 |
+
/**
|
274 |
+
* @static
|
275 |
+
* @param $userID
|
276 |
+
* @param $sharedkey
|
277 |
+
* @return string
|
278 |
+
*/
|
279 |
+
public function encryptReviewerId($userID)
|
280 |
+
{
|
281 |
+
$sharedKey = Mage::getStoreConfig('bazaarvoice/general/EncodingKey');
|
282 |
+
$userStr = 'date=' . date('Ymd') . '&userid=' . $userID;
|
283 |
+
return md5($sharedKey . $userStr) . bin2hex($userStr);
|
284 |
+
}
|
285 |
+
|
286 |
+
/**
|
287 |
+
* @static
|
288 |
+
* @param $isStatic boolean indicating whether or not to return a URL to fetch static BV resources
|
289 |
+
* @param $bvProduct String indicating the BV product to get the URL for ('reviews', 'questions')
|
290 |
+
* @return string
|
291 |
+
*/
|
292 |
+
public function getBvUrl($isStatic, $bvProduct)
|
293 |
+
{
|
294 |
+
$protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != '') ? 'https' : 'http';
|
295 |
+
$hostSubdomain = $this->getSubDomainForBVProduct($bvProduct);
|
296 |
+
$hostDomain = 'ugc.bazaarvoice.com';
|
297 |
+
$bvStaging = $this->getBvStaging();
|
298 |
+
$deploymentZone = $this->getDeploymentZoneForBVProduct($bvProduct);
|
299 |
+
$stat = ($isStatic === 1) ? 'static/' : '';
|
300 |
+
|
301 |
+
return $protocol . '://' . $hostSubdomain . '.' . $hostDomain . $bvStaging . $stat . $deploymentZone;
|
302 |
+
}
|
303 |
+
|
304 |
+
/**
|
305 |
+
* Get url to bvapi.js javascript API file
|
306 |
+
*
|
307 |
+
* C2013 staging call:
|
308 |
+
* ----------------------
|
309 |
+
* <code>
|
310 |
+
* src="//display-stg.ugc.bazaarvoice.com/static/{{ClientName}}/{{DeploymentZoneName}}/{{Locale}}/bvapi.js"
|
311 |
+
* </code>
|
312 |
+
*
|
313 |
+
* @static
|
314 |
+
* @param $isStatic
|
315 |
+
* @return string
|
316 |
+
*/
|
317 |
+
public function getBvApiHostUrl($isStatic, $store = null)
|
318 |
+
{
|
319 |
+
// Build protocol based on current page
|
320 |
+
$protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != '') ? 'https' : 'http';
|
321 |
+
// Build hostname based on environment setting
|
322 |
+
$environment = Mage::getStoreConfig('bazaarvoice/general/environment', $store);
|
323 |
+
if ($environment == 'staging') {
|
324 |
+
$apiHostname = 'display-stg.ugc.bazaarvoice.com';
|
325 |
+
}
|
326 |
+
else {
|
327 |
+
$apiHostname = 'display.ugc.bazaarvoice.com';
|
328 |
+
}
|
329 |
+
// Build static dir name based on param
|
330 |
+
if($isStatic) {
|
331 |
+
$static = 'static/';
|
332 |
+
}
|
333 |
+
else {
|
334 |
+
$static = '';
|
335 |
+
}
|
336 |
+
// Lookup other config settings
|
337 |
+
$clientName = Mage::getStoreConfig('bazaarvoice/general/client_name', $store);
|
338 |
+
$deploymnetZoneName = Mage::getStoreConfig('bazaarvoice/general/deployment_zone', $store);
|
339 |
+
// Get locale code from BV config,
|
340 |
+
// Note that this doesn't use Magento's locale, this will allow clients to override this and map it as they see fit
|
341 |
+
$localeCode = Mage::getStoreConfig('bazaarvoice/general/locale', $store);
|
342 |
+
// Build url string
|
343 |
+
$url = $protocol . '://' . $apiHostname . '/' . $static . $clientName . '/' . urlencode($deploymnetZoneName) . '/' . $localeCode;
|
344 |
+
// Return final url
|
345 |
+
return $url;
|
346 |
+
}
|
347 |
+
|
348 |
+
/**
|
349 |
+
* @static
|
350 |
+
* @return string Either returns '/' or '/bvstaging/'
|
351 |
+
*/
|
352 |
+
public function getBvStaging()
|
353 |
+
{
|
354 |
+
$environment = Mage::getStoreConfig('bazaarvoice/general/environment');
|
355 |
+
if ($environment == 'staging') {
|
356 |
+
$bvStaging = '/bvstaging/';
|
357 |
+
}
|
358 |
+
else {
|
359 |
+
$bvStaging = '/';
|
360 |
+
}
|
361 |
+
return $bvStaging;
|
362 |
+
}
|
363 |
+
|
364 |
+
public function getSFTPHost($store = null)
|
365 |
+
{
|
366 |
+
$environment = Mage::getStoreConfig('bazaarvoice/general/environment', $store);
|
367 |
+
$ftpHostOverride = trim(Mage::getStoreConfig('bazaarvoice/bv_config/ftp_host_name', $store));
|
368 |
+
if(strlen($ftpHostOverride)) {
|
369 |
+
$sftpHost = $ftpHostOverride;
|
370 |
+
}
|
371 |
+
else if ($environment == 'staging') {
|
372 |
+
$sftpHost = 'ftp-stg.bazaarvoice.com';
|
373 |
+
}
|
374 |
+
else {
|
375 |
+
$sftpHost = 'ftp.bazaarvoice.com';
|
376 |
+
}
|
377 |
+
return $sftpHost;
|
378 |
+
}
|
379 |
+
|
380 |
+
/**
|
381 |
+
* @static
|
382 |
+
* @return string representing the default display code to be used across all available BV products
|
383 |
+
*/
|
384 |
+
public function getDefaultDeploymentZone()
|
385 |
+
{
|
386 |
+
return Mage::getStoreConfig('bazaarvoice/general/deployment_zone');
|
387 |
+
}
|
388 |
+
|
389 |
+
/**
|
390 |
+
* @static
|
391 |
+
* @param $bvProduct String indicating the BV product to get the displaycode for ('reviews', 'questions')
|
392 |
+
* @return string
|
393 |
+
*/
|
394 |
+
public function getDeploymentZoneForBVProduct($bvProduct)
|
395 |
+
{
|
396 |
+
return getDefaultDeploymentZone();
|
397 |
+
}
|
398 |
+
|
399 |
+
/**
|
400 |
+
* @static
|
401 |
+
* @param $bvProduct String indicating the BV product to get the sub-domain for ('reviews', 'questions')
|
402 |
+
* @return string
|
403 |
+
*/
|
404 |
+
public function getSubDomainForBVProduct($bvProduct)
|
405 |
+
{
|
406 |
+
return $this->getConfigPropertyForBVProduct($bvProduct, 'SubDomain');
|
407 |
+
}
|
408 |
+
|
409 |
+
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
410 |
+
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
411 |
+
|
412 |
+
public function getConfigPropertyForBVProduct($bvProduct, $propertyName)
|
413 |
+
{
|
414 |
+
$code = 'rr';
|
415 |
+
if ($bvProduct === 'questions') {
|
416 |
+
$code = 'qa';
|
417 |
+
}
|
418 |
+
|
419 |
+
return Mage::getStoreConfig('bazaarvoice/'.$code.'/'.$propertyName);
|
420 |
+
}
|
421 |
+
|
422 |
+
public function sendNotificationEmail($subject, $text)
|
423 |
+
{
|
424 |
+
$toEmail = Mage::getStoreConfig('bazaarvoice/feeds/admin_email');
|
425 |
+
$fromEmail = Mage::getStoreConfig('trans_email/ident_general/email'); // The 'General' contact identity is a default setting in Magento
|
426 |
+
if (empty($fromEmail)) {
|
427 |
+
$fromEmail = $toEmail;
|
428 |
+
}
|
429 |
+
|
430 |
+
if (!empty($toEmail)) {
|
431 |
+
/*
|
432 |
+
* Loads the template file from
|
433 |
+
* app/locale/en_US/template/email/bazaarvoice_notification.html
|
434 |
+
*/
|
435 |
+
$emailTemplate = Mage::getModel('core/email_template')->loadDefault('bazaarvoice_notification_template');
|
436 |
+
|
437 |
+
// Create an array of variables to assign to template
|
438 |
+
$emailTemplateVariables = array();
|
439 |
+
$emailTemplateVariables['text'] = $text;
|
440 |
+
|
441 |
+
$emailTemplate->setSenderName('Bazaarvoice Magento Notifier');
|
442 |
+
$emailTemplate->setSenderEmail($fromEmail);
|
443 |
+
$emailTemplate->setTemplateSubject($subject);
|
444 |
+
|
445 |
+
$emailTemplate->send($toEmail,'Bazaarvoice Admin', $emailTemplateVariables);
|
446 |
+
}
|
447 |
+
}
|
448 |
+
|
449 |
+
/**
|
450 |
+
* Returns the product unless the product visibility is
|
451 |
+
* set to not visible. In this case, it will try and pull
|
452 |
+
* the parent/associated product from the order item.
|
453 |
+
*
|
454 |
+
* @param Mage_Sales_Model_Order_Item $item
|
455 |
+
* @return Mage_Catalog_Model_Product
|
456 |
+
*/
|
457 |
+
public function getReviewableProductFromOrderItem($item)
|
458 |
+
{
|
459 |
+
$product = Mage::getModel('catalog/product');
|
460 |
+
$product->setStoreId($item->getStoreId());
|
461 |
+
$product->load($item->getProductId());
|
462 |
+
if ($product->getVisibility() == Mage_Catalog_Model_Product_Visibility::VISIBILITY_NOT_VISIBLE)
|
463 |
+
{
|
464 |
+
$options = $item->getProductOptions();
|
465 |
+
try
|
466 |
+
{
|
467 |
+
$parentId = $options['super_product_config']['product_id'];
|
468 |
+
$product = Mage::getModel('catalog/product')->load($parentId);
|
469 |
+
}
|
470 |
+
catch (Exception $ex) {}
|
471 |
+
}
|
472 |
+
|
473 |
+
return $product;
|
474 |
+
}
|
475 |
+
|
476 |
+
/**
|
477 |
+
*
|
478 |
+
*/
|
479 |
+
public function getExtensionVersion()
|
480 |
+
{
|
481 |
+
return (string) Mage::getConfig()->getNode()->modules->Bazaarvoice_Connector->version;
|
482 |
+
}
|
483 |
+
|
484 |
+
}
|
app/code/local/Bazaarvoice/Connector/Model/ExportProductFeed.php
ADDED
@@ -0,0 +1,386 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
// @codingStandardsIgnoreStart
|
3 |
+
/**
|
4 |
+
* Event observer and indexer running application
|
5 |
+
*
|
6 |
+
* @author Bazaarvoice, Inc.
|
7 |
+
*/
|
8 |
+
// @codingStandardsIgnoreEnd
|
9 |
+
|
10 |
+
/**
|
11 |
+
*
|
12 |
+
* Bazaarvoice product feed should be in the following format:
|
13 |
+
*
|
14 |
+
* <?xml version="1.0" encoding="UTF-8"?>
|
15 |
+
* <Feed xmlns="http://www.bazaarvoice.com/xs/PRR/ProductFeed/5.2"
|
16 |
+
* name="SiteName"
|
17 |
+
* incremental="false"
|
18 |
+
* extractDate="2007-01-01T12:00:00.000000">
|
19 |
+
* <Categories>
|
20 |
+
* <Category>
|
21 |
+
* <ExternalId>1010</ExternalId>
|
22 |
+
* <Name>First Category</Name>
|
23 |
+
* <CategoryPageUrl>http://www.site.com/category.htm?cat=1010</CategoryPageUrl>
|
24 |
+
* </Category>
|
25 |
+
* ..... 0-n categories
|
26 |
+
* </Categories>
|
27 |
+
* <Products>
|
28 |
+
* <Product>
|
29 |
+
* <ExternalId>2000001</ExternalId>
|
30 |
+
* <Name>First Product</Name>
|
31 |
+
* <Description>First Product Description Text</Description>
|
32 |
+
* <Brand>ProductBrand</Brand>
|
33 |
+
* <CategoryExternalId>1010</CategoryExternalId>
|
34 |
+
* <ProductPageUrl>http://www.site.com/product.htm?prod=2000001</ProductPageUrl>
|
35 |
+
* <ImageUrl>http://images.site.com/prodimages/2000001.gif</ImageUrl>
|
36 |
+
* <ManufacturerPartNumber>26-12345-8Z</ManufacturerPartNumber>
|
37 |
+
* <EAN>0213354752286</EAN>
|
38 |
+
* </Product>
|
39 |
+
* ....... 0-n products
|
40 |
+
* </Products>
|
41 |
+
*</Feed>
|
42 |
+
*/
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Product Feed Export Class
|
46 |
+
*/
|
47 |
+
class Bazaarvoice_Connector_Model_ExportProductFeed extends Mage_Core_Model_Abstract
|
48 |
+
{
|
49 |
+
|
50 |
+
protected function _construct()
|
51 |
+
{
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
*
|
56 |
+
* process daily feed for the Bazaarvoice. The feed will be FTPed to the BV FTP server
|
57 |
+
*
|
58 |
+
* Product & Catalog Feed to BV
|
59 |
+
*
|
60 |
+
*/
|
61 |
+
public function exportDailyProductFeed()
|
62 |
+
{
|
63 |
+
// Log
|
64 |
+
Mage::log('Start Bazaarvoice product feed generation');
|
65 |
+
// Check global setting to see what at which scope / level we should generate feeds
|
66 |
+
$feedGenScope = Mage::getStoreConfig('bazaarvoice/feeds/generation_scope');
|
67 |
+
switch ($feedGenScope) {
|
68 |
+
case Bazaarvoice_Connector_Model_Source_FeedGenerationScope::SCOPE_WEBSITE:
|
69 |
+
$this->exportDailyProductFeedByWebsite();
|
70 |
+
break;
|
71 |
+
case Bazaarvoice_Connector_Model_Source_FeedGenerationScope::SCOPE_STORE_GROUP:
|
72 |
+
$this->exportDailyProductFeedByGroup();
|
73 |
+
break;
|
74 |
+
case Bazaarvoice_Connector_Model_Source_FeedGenerationScope::SCOPE_STORE_VIEW:
|
75 |
+
$this->exportDailyProductFeedByStore();
|
76 |
+
break;
|
77 |
+
}
|
78 |
+
// Log
|
79 |
+
Mage::log('End Bazaarvoice product feed generation');
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
*
|
84 |
+
*/
|
85 |
+
private function exportDailyProductFeedByWebsite()
|
86 |
+
{
|
87 |
+
// Log
|
88 |
+
Mage::log('Exporting product feed file for each website...');
|
89 |
+
// Iterate through all websites in this instance
|
90 |
+
// (Not the 'admin' store view, which represents admin panel)
|
91 |
+
$websites = Mage::app()->getWebsites(false);
|
92 |
+
/** @var $website Mage_Core_Model_Website */
|
93 |
+
foreach ($websites as $website) {
|
94 |
+
try {
|
95 |
+
if (Mage::getStoreConfig('bazaarvoice/feeds/enable_product_feed', $website->getDefaultGroup()->getDefaultStoreId()) ===
|
96 |
+
'1'
|
97 |
+
&& Mage::getStoreConfig('bazaarvoice/general/enable_bv', $website->getDefaultGroup()->getDefaultStoreId()) === '1'
|
98 |
+
) {
|
99 |
+
if (count($website->getStores()) > 0) {
|
100 |
+
Mage::log(' BV - Exporting product feed for website: ' . $website->getName(),
|
101 |
+
Zend_Log::INFO);
|
102 |
+
$this->exportDailyProductFeedForWebsite($website);
|
103 |
+
}
|
104 |
+
else {
|
105 |
+
Mage::throwException('No stores for website: ' . $website->getName());
|
106 |
+
}
|
107 |
+
}
|
108 |
+
else {
|
109 |
+
Mage::log(' BV - Product feed disabled for website: ' . $website->getName(), Zend_Log::INFO);
|
110 |
+
}
|
111 |
+
}
|
112 |
+
catch (Exception $e) {
|
113 |
+
Mage::log(' BV - Failed to export daily product feed for website: ' . $website->getName(),
|
114 |
+
Zend_Log::ERR);
|
115 |
+
Mage::log(' BV - Error message: ' . $e->getMessage(), Zend_Log::ERR);
|
116 |
+
Mage::logException($e);
|
117 |
+
// Continue processing other websites
|
118 |
+
}
|
119 |
+
}
|
120 |
+
}
|
121 |
+
|
122 |
+
/**
|
123 |
+
*
|
124 |
+
*/
|
125 |
+
public function exportDailyProductFeedByGroup()
|
126 |
+
{
|
127 |
+
// Log
|
128 |
+
Mage::log('Exporting product feed file for each store group...');
|
129 |
+
// Iterate through all stores / groups in this instance
|
130 |
+
// (Not the 'admin' store view, which represents admin panel)
|
131 |
+
$groups = Mage::app()->getGroups(false);
|
132 |
+
/** @var $group Mage_Core_Model_Store_Group */
|
133 |
+
foreach ($groups as $group) {
|
134 |
+
try {
|
135 |
+
if (Mage::getStoreConfig('bazaarvoice/feeds/enable_product_feed', $group->getDefaultStoreId()) === '1'
|
136 |
+
&& Mage::getStoreConfig('bazaarvoice/general/enable_bv', $group->getDefaultStoreId()) === '1'
|
137 |
+
) {
|
138 |
+
if (count($group->getStores()) > 0) {
|
139 |
+
Mage::log(' BV - Exporting product feed for store group: ' . $group->getName(), Zend_Log::INFO);
|
140 |
+
$this->exportDailyProductFeedForStoreGroup($group);
|
141 |
+
}
|
142 |
+
else {
|
143 |
+
Mage::throwException('No stores for store group: ' . $group->getName());
|
144 |
+
}
|
145 |
+
}
|
146 |
+
else {
|
147 |
+
Mage::log(' BV - Product feed disabled for store group: ' . $group->getName(), Zend_Log::INFO);
|
148 |
+
}
|
149 |
+
}
|
150 |
+
catch (Exception $e) {
|
151 |
+
Mage::log(' BV - Failed to export daily product feed for store group: ' . $group->getName(),
|
152 |
+
Zend_Log::ERR);
|
153 |
+
Mage::log(' BV - Error message: ' . $e->getMessage(), Zend_Log::ERR);
|
154 |
+
Mage::logException($e);
|
155 |
+
// Continue processing other store groups
|
156 |
+
}
|
157 |
+
}
|
158 |
+
}
|
159 |
+
|
160 |
+
/**
|
161 |
+
*
|
162 |
+
*/
|
163 |
+
private function exportDailyProductFeedByStore()
|
164 |
+
{
|
165 |
+
// Log
|
166 |
+
Mage::log('Exporting product feed file for each store / store view...');
|
167 |
+
// Iterate through all stores / groups in this instance
|
168 |
+
// (Not the 'admin' store view, which represents admin panel)
|
169 |
+
$stores = Mage::app()->getStores(false);
|
170 |
+
/** @var $store Mage_Core_Model_Store */
|
171 |
+
foreach ($stores as $store) {
|
172 |
+
try {
|
173 |
+
if (Mage::getStoreConfig('bazaarvoice/feeds/enable_product_feed', $store->getId()) === '1'
|
174 |
+
&& Mage::getStoreConfig('bazaarvoice/general/enable_bv', $store->getId()) === '1'
|
175 |
+
) {
|
176 |
+
Mage::log(' BV - Exporting product feed for store: ' . $store->getCode(), Zend_Log::INFO);
|
177 |
+
$this->exportDailyProductFeedForStore($store);
|
178 |
+
}
|
179 |
+
else {
|
180 |
+
Mage::log(' BV - Product feed disabled for store: ' . $store->getCode(), Zend_Log::INFO);
|
181 |
+
}
|
182 |
+
}
|
183 |
+
catch (Exception $e) {
|
184 |
+
Mage::log(' BV - Failed to export daily product feed for store: ' . $store->getCode(), Zend_Log::ERR);
|
185 |
+
Mage::log(' BV - Error message: ' . $e->getMessage(), Zend_Log::ERR);
|
186 |
+
Mage::logException($e);
|
187 |
+
// Continue processing other store groups
|
188 |
+
}
|
189 |
+
}
|
190 |
+
}
|
191 |
+
|
192 |
+
/**
|
193 |
+
* process daily feed for the Bazaarvoice. The feed will be FTPed to the BV FTP server
|
194 |
+
*
|
195 |
+
* Product & Catalog Feed to BV
|
196 |
+
*
|
197 |
+
* @param Mage_Core_Model_Website $website Website
|
198 |
+
*
|
199 |
+
*/
|
200 |
+
public function exportDailyProductFeedForWebsite(Mage_Core_Model_Website $website)
|
201 |
+
{
|
202 |
+
/** @var Bazaarvoice_Connector_Model_ProductFeed_Category $categoryModel */
|
203 |
+
$categoryModel = Mage::getModel('bazaarvoice/productFeed_category');
|
204 |
+
/** @var Bazaarvoice_Connector_Model_ProductFeed_Product $productModel */
|
205 |
+
$productModel = Mage::getModel('bazaarvoice/productFeed_product');
|
206 |
+
/** @var Bazaarvoice_Connector_Model_ProductFeed_Brand $brandModel */
|
207 |
+
$brandModel = Mage::getModel('bazaarvoice/productFeed_brand');
|
208 |
+
|
209 |
+
// Build local file name / path
|
210 |
+
$productFeedFilePath = Mage::getBaseDir('var') . DS . 'export' . DS . 'bvfeeds';
|
211 |
+
$productFeedFileName =
|
212 |
+
$productFeedFilePath . DS . 'productFeed-website-' . $website->getId() . '-' . date('U') . '.xml';
|
213 |
+
// Get client name for the scope
|
214 |
+
$clientName = Mage::getStoreConfig('bazaarvoice/general/client_name', $website->getDefaultGroup()->getDefaultStoreId());
|
215 |
+
|
216 |
+
// Create varien io object and write local feed file
|
217 |
+
/* @var $ioObject Varien_Io_File */
|
218 |
+
$ioObject = $this->createAndStartWritingFile($productFeedFileName, $clientName);
|
219 |
+
Mage::log(' BV - processing all categories');
|
220 |
+
$categoryModel->processCategoriesForWebsite($ioObject, $website);
|
221 |
+
Mage::log(' BV - completed categories, beginning products');
|
222 |
+
$productModel->setCategoryIdList($categoryModel->getCategoryIdList());
|
223 |
+
$productModel->processProductsForWebsite($ioObject, $website);
|
224 |
+
Mage::log(' BV - completed products, beginning brands');
|
225 |
+
$brandModel->processBrandsForWebsite($ioObject, $website);
|
226 |
+
Mage::log(' BV - completed processing all brands');
|
227 |
+
$this->closeAndFinishWritingFile($ioObject);
|
228 |
+
|
229 |
+
// Upload feed
|
230 |
+
$this->uploadFeed($productFeedFileName, $website->getDefaultStore());
|
231 |
+
|
232 |
+
}
|
233 |
+
|
234 |
+
/**
|
235 |
+
* process daily feed for the Bazaarvoice. The feed will be FTPed to the BV FTP server
|
236 |
+
*
|
237 |
+
* Product & Catalog Feed to BV
|
238 |
+
*
|
239 |
+
* @param Mage_Core_Model_Store_Group $group Store Group
|
240 |
+
*
|
241 |
+
*/
|
242 |
+
public function exportDailyProductFeedForStoreGroup(Mage_Core_Model_Store_Group $group)
|
243 |
+
{
|
244 |
+
/** @var Bazaarvoice_Connector_Model_ProductFeed_Category $categoryModel */
|
245 |
+
$categoryModel = Mage::getModel('bazaarvoice/productFeed_category');
|
246 |
+
/** @var Bazaarvoice_Connector_Model_ProductFeed_Product $productModel */
|
247 |
+
$productModel = Mage::getModel('bazaarvoice/productFeed_product');
|
248 |
+
/** @var Bazaarvoice_Connector_Model_ProductFeed_Brand $brandModel */
|
249 |
+
$brandModel = Mage::getModel('bazaarvoice/productFeed_brand');
|
250 |
+
|
251 |
+
// Build local file name / path
|
252 |
+
$productFeedFilePath = Mage::getBaseDir('var') . DS . 'export' . DS . 'bvfeeds';
|
253 |
+
$productFeedFileName =
|
254 |
+
$productFeedFilePath . DS . 'productFeed-group-' . $group->getId() . '-' . date('U') . '.xml';
|
255 |
+
// Get client name for the scope
|
256 |
+
$clientName = Mage::getStoreConfig('bazaarvoice/general/client_name', $group->getDefaultStoreId());
|
257 |
+
|
258 |
+
// Create varien io object and write local feed file
|
259 |
+
/* @var $ioObject Varien_Io_File */
|
260 |
+
$ioObject = $this->createAndStartWritingFile($productFeedFileName, $clientName);
|
261 |
+
Mage::log(' BV - processing all categories');
|
262 |
+
$categoryModel->processCategoriesForGroup($ioObject, $group);
|
263 |
+
Mage::log(' BV - completed categories, beginning products');
|
264 |
+
$productModel->setCategoryIdList($categoryModel->getCategoryIdList());
|
265 |
+
$productModel->processProductsForGroup($ioObject, $group);
|
266 |
+
Mage::log(' BV - completed products, beginning brands');
|
267 |
+
$brandModel->processBrandsForGroup($ioObject, $group);
|
268 |
+
Mage::log(' BV - completed processing all brands');
|
269 |
+
$this->closeAndFinishWritingFile($ioObject);
|
270 |
+
|
271 |
+
// Upload feed
|
272 |
+
$this->uploadFeed($productFeedFileName, $group->getDefaultStore());
|
273 |
+
|
274 |
+
}
|
275 |
+
|
276 |
+
/**
|
277 |
+
* process daily feed for the Bazaarvoice. The feed will be FTPed to the BV FTP server
|
278 |
+
*
|
279 |
+
* Product & Catalog Feed to BV
|
280 |
+
* @param Mage_Core_Model_Store $store
|
281 |
+
*
|
282 |
+
*/
|
283 |
+
public function exportDailyProductFeedForStore(Mage_Core_Model_Store $store)
|
284 |
+
{
|
285 |
+
/** @var Bazaarvoice_Connector_Model_ProductFeed_Category $categoryModel */
|
286 |
+
$categoryModel = Mage::getModel('bazaarvoice/productFeed_category');
|
287 |
+
/** @var Bazaarvoice_Connector_Model_ProductFeed_Product $productModel */
|
288 |
+
$productModel = Mage::getModel('bazaarvoice/productFeed_product');
|
289 |
+
/** @var Bazaarvoice_Connector_Model_ProductFeed_Brand $brandModel */
|
290 |
+
$brandModel = Mage::getModel('bazaarvoice/productFeed_brand');
|
291 |
+
|
292 |
+
// Build local file name / path
|
293 |
+
$productFeedFilePath = Mage::getBaseDir('var') . DS . 'export' . DS . 'bvfeeds';
|
294 |
+
$productFeedFileName =
|
295 |
+
$productFeedFilePath . DS . 'productFeed-store-' . $store->getId() . '-' . date('U') . '.xml';
|
296 |
+
// Get client name for the scope
|
297 |
+
$clientName = Mage::getStoreConfig('bazaarvoice/general/client_name', $store->getId());
|
298 |
+
|
299 |
+
// Create varien io object and write local feed file
|
300 |
+
/* @var $ioObject Varien_Io_File */
|
301 |
+
$ioObject = $this->createAndStartWritingFile($productFeedFileName, $clientName);
|
302 |
+
Mage::log(' BV - processing all categories');
|
303 |
+
$categoryModel->processCategoriesForStore($ioObject, $store);
|
304 |
+
Mage::log(' BV - completed categories, beginning products');
|
305 |
+
$productModel->setCategoryIdList($categoryModel->getCategoryIdList());
|
306 |
+
$productModel->processProductsForStore($ioObject, $store);
|
307 |
+
Mage::log(' BV - completed products, beginning brands');
|
308 |
+
$brandModel->processBrandsForStore($ioObject, $store);
|
309 |
+
Mage::log(' BV - completed processing all brands');
|
310 |
+
$this->closeAndFinishWritingFile($ioObject);
|
311 |
+
|
312 |
+
// Upload feed
|
313 |
+
$this->uploadFeed($productFeedFileName, $store);
|
314 |
+
|
315 |
+
}
|
316 |
+
|
317 |
+
/**
|
318 |
+
* @param $productFeedFileName
|
319 |
+
* @param Mage_Core_Model_Store $store
|
320 |
+
*/
|
321 |
+
private function uploadFeed($productFeedFileName, Mage_Core_Model_Store $store)
|
322 |
+
{
|
323 |
+
// Get ref to BV helper
|
324 |
+
/* @var $bvHelper Bazaarvoice_Connector_Helper_Data */
|
325 |
+
$bvHelper = Mage::helper('bazaarvoice');
|
326 |
+
|
327 |
+
// Get path and filename from custom config settings
|
328 |
+
$destinationFile = Mage::getStoreConfig('bazaarvoice/bv_config/product_feed_export_export_path', $store->getId()) . '/' .
|
329 |
+
Mage::getStoreConfig('bazaarvoice/bv_config/product_feed_export_filename', $store->getId());
|
330 |
+
$sourceFile = $productFeedFileName;
|
331 |
+
$upload = $bvHelper->uploadFile($sourceFile, $destinationFile, $store);
|
332 |
+
|
333 |
+
if (!$upload) {
|
334 |
+
Mage::log(' Bazaarvoice FTP upload failed! [filename = ' . $productFeedFileName . ']');
|
335 |
+
}
|
336 |
+
else {
|
337 |
+
Mage::log(' Bazaarvoice FTP upload success! [filename = ' . $productFeedFileName . ']');
|
338 |
+
$ioObject = new Varien_Io_File();
|
339 |
+
$ioObject->rm($productFeedFileName);
|
340 |
+
}
|
341 |
+
}
|
342 |
+
|
343 |
+
/**
|
344 |
+
* @param string $productFeedFileName Name of local product feed file to create and write
|
345 |
+
* @param string $clientName BV Client name text
|
346 |
+
* @return Varien_Io_File File object, opening <Feed> tag is already written
|
347 |
+
*/
|
348 |
+
private function createAndStartWritingFile($productFeedFileName, $clientName)
|
349 |
+
{
|
350 |
+
// Get ref to BV helper
|
351 |
+
/* @var $bvHelper Bazaarvoice_Connector_Helper_Data */
|
352 |
+
$bvHelper = Mage::helper('bazaarvoice');
|
353 |
+
|
354 |
+
$ioObject = new Varien_Io_File();
|
355 |
+
try {
|
356 |
+
$ioObject->open(array('path' => dirname($productFeedFileName)));
|
357 |
+
}
|
358 |
+
catch (Exception $e) {
|
359 |
+
$ioObject->mkdir(dirname($productFeedFileName), 0777, true);
|
360 |
+
$ioObject->open(array('path' => dirname($productFeedFileName)));
|
361 |
+
}
|
362 |
+
|
363 |
+
if (!$ioObject->streamOpen(basename($productFeedFileName))) {
|
364 |
+
Mage::throwException('Failed to open local feed file for writing: ' . $productFeedFileName);
|
365 |
+
}
|
366 |
+
|
367 |
+
$ioObject->streamWrite("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" .
|
368 |
+
"<Feed xmlns=\"http://www.bazaarvoice.com/xs/PRR/ProductFeed/5.2\"" .
|
369 |
+
" generator=\"Magento Extension r" . $bvHelper->getExtensionVersion() . "\"" .
|
370 |
+
" name=\"" . $clientName . "\"" .
|
371 |
+
" incremental=\"false\"" .
|
372 |
+
" extractDate=\"" . date('Y-m-d') . "T" . date('H:i:s') . ".000000\">\n");
|
373 |
+
|
374 |
+
return $ioObject;
|
375 |
+
}
|
376 |
+
|
377 |
+
/**
|
378 |
+
* @param Varien_Io_File $ioObject File object for feed file
|
379 |
+
*/
|
380 |
+
private function closeAndFinishWritingFile(Varien_Io_File $ioObject)
|
381 |
+
{
|
382 |
+
$ioObject->streamWrite("</Feed>\n");
|
383 |
+
$ioObject->streamClose();
|
384 |
+
}
|
385 |
+
|
386 |
+
}
|
app/code/local/Bazaarvoice/Connector/Model/ExportPurchaseFeed.php
ADDED
@@ -0,0 +1,639 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
class Bazaarvoice_Connector_Model_ExportPurchaseFeed extends Mage_Core_Model_Abstract
|
3 |
+
{
|
4 |
+
|
5 |
+
const ALREADY_SENT_IN_FEED_FLAG = 'sent_in_bv_postpurchase_feed';
|
6 |
+
const TRIGGER_EVENT_PURCHASE = 'purchase';
|
7 |
+
const TRIGGER_EVENT_SHIP = 'ship';
|
8 |
+
|
9 |
+
const NUM_DAYS_LOOKBACK = 30;
|
10 |
+
|
11 |
+
const DEBUG_OUTPUT = false;
|
12 |
+
|
13 |
+
protected function _construct()
|
14 |
+
{
|
15 |
+
}
|
16 |
+
|
17 |
+
public function exportPurchaseFeed()
|
18 |
+
{
|
19 |
+
// Log
|
20 |
+
Mage::log('Start Bazaarvoice purchase feed generation');
|
21 |
+
// Check global setting to see what at which scope / level we should generate feeds
|
22 |
+
$feedGenScope = Mage::getStoreConfig('bazaarvoice/feeds/generation_scope');
|
23 |
+
switch ($feedGenScope) {
|
24 |
+
case Bazaarvoice_Connector_Model_Source_FeedGenerationScope::SCOPE_WEBSITE:
|
25 |
+
$this->exportPurchaseFeedByWebsite();
|
26 |
+
break;
|
27 |
+
case Bazaarvoice_Connector_Model_Source_FeedGenerationScope::SCOPE_STORE_GROUP:
|
28 |
+
$this->exportPurchaseFeedByGroup();
|
29 |
+
break;
|
30 |
+
case Bazaarvoice_Connector_Model_Source_FeedGenerationScope::SCOPE_STORE_VIEW:
|
31 |
+
$this->exportPurchaseFeedByStore();
|
32 |
+
break;
|
33 |
+
}
|
34 |
+
// Log
|
35 |
+
Mage::log('End Bazaarvoice purchase feed generation');
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
*
|
40 |
+
*/
|
41 |
+
public function exportPurchaseFeedByWebsite()
|
42 |
+
{
|
43 |
+
// Log
|
44 |
+
Mage::log('Exporting purchase feed file for each website...');
|
45 |
+
// Iterate through all websites in this instance
|
46 |
+
// (Not the 'admin' website / store / view, which represents admin panel)
|
47 |
+
$websites = Mage::app()->getWebsites(false);
|
48 |
+
/** @var $website Mage_Core_Model_Website */
|
49 |
+
foreach ($websites as $website) {
|
50 |
+
try {
|
51 |
+
if (Mage::getStoreConfig('bazaarvoice/feeds/enable_purchase_feed', $website->getDefaultGroup()->getDefaultStoreId()) === '1'
|
52 |
+
&& Mage::getStoreConfig('bazaarvoice/general/enable_bv', $website->getDefaultGroup()->getDefaultStoreId()) === '1'
|
53 |
+
) {
|
54 |
+
if (count($website->getStores()) > 0) {
|
55 |
+
Mage::log(' BV - Exporting purchase feed for website: ' . $website->getName(), Zend_Log::INFO);
|
56 |
+
$this->exportPurchaseFeedForWebsite($website);
|
57 |
+
}
|
58 |
+
else {
|
59 |
+
Mage::throwException('No stores for website: ' . $website->getName());
|
60 |
+
}
|
61 |
+
}
|
62 |
+
else {
|
63 |
+
Mage::log(' BV - Purchase feed disabled for website: ' . $website->getName(), Zend_Log::INFO);
|
64 |
+
}
|
65 |
+
}
|
66 |
+
catch (Exception $e) {
|
67 |
+
Mage::log(' BV - Failed to export daily purchase feed for website: ' . $website->getName(), Zend_Log::ERR);
|
68 |
+
Mage::log(' BV - Error message: ' . $e->getMessage(), Zend_Log::ERR);
|
69 |
+
Mage::logException($e);
|
70 |
+
// Continue processing other websites
|
71 |
+
}
|
72 |
+
}
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
*
|
77 |
+
*/
|
78 |
+
public function exportPurchaseFeedByGroup()
|
79 |
+
{
|
80 |
+
// Log
|
81 |
+
Mage::log('Exporting purchase feed file for each store group...');
|
82 |
+
// Iterate through all stores / groups in this instance
|
83 |
+
// (Not the 'admin' store view, which represents admin panel)
|
84 |
+
$groups = Mage::app()->getGroups(false);
|
85 |
+
/** @var $group Mage_Core_Model_Store_Group */
|
86 |
+
foreach ($groups as $group) {
|
87 |
+
try {
|
88 |
+
if (Mage::getStoreConfig('bazaarvoice/feeds/enable_purchase_feed', $group->getDefaultStoreId()) === '1'
|
89 |
+
&& Mage::getStoreConfig('bazaarvoice/general/enable_bv', $group->getDefaultStoreId()) === '1'
|
90 |
+
) {
|
91 |
+
if (count($group->getStores()) > 0) {
|
92 |
+
Mage::log(' BV - Exporting purchase feed for store group: ' . $group->getName(), Zend_Log::INFO);
|
93 |
+
$this->exportPurchaseFeedForStoreGroup($group);
|
94 |
+
}
|
95 |
+
else {
|
96 |
+
Mage::throwException('No stores for store group: ' . $group->getName());
|
97 |
+
}
|
98 |
+
}
|
99 |
+
else {
|
100 |
+
Mage::log(' BV - Purchase feed disabled for store group: ' . $group->getName(), Zend_Log::INFO);
|
101 |
+
}
|
102 |
+
}
|
103 |
+
catch (Exception $e) {
|
104 |
+
Mage::log(' BV - Failed to export daily purchase feed for store group: ' . $group->getName(), Zend_Log::ERR);
|
105 |
+
Mage::log(' BV - Error message: ' . $e->getMessage(), Zend_Log::ERR);
|
106 |
+
Mage::logException($e);
|
107 |
+
// Continue processing other store groups
|
108 |
+
}
|
109 |
+
}
|
110 |
+
}
|
111 |
+
|
112 |
+
/**
|
113 |
+
*
|
114 |
+
*/
|
115 |
+
public function exportPurchaseFeedByStore()
|
116 |
+
{
|
117 |
+
// Log
|
118 |
+
Mage::log('Exporting purchase feed file for each store...');
|
119 |
+
// Iterate through all stores in this instance
|
120 |
+
// (Not the 'admin' store view, which represents admin panel)
|
121 |
+
$stores = Mage::app()->getStores(false);
|
122 |
+
/** @var $store Mage_Core_Model_Store */
|
123 |
+
foreach ($stores as $store) {
|
124 |
+
try {
|
125 |
+
if (Mage::getStoreConfig('bazaarvoice/feeds/enable_purchase_feed', $store->getId()) === '1'
|
126 |
+
&& Mage::getStoreConfig('bazaarvoice/general/enable_bv', $store->getId()) === '1'
|
127 |
+
) {
|
128 |
+
Mage::log(' BV - Exporting purchase feed for: ' . $store->getCode(), Zend_Log::INFO);
|
129 |
+
$this->exportPurchaseFeedForStore($store);
|
130 |
+
}
|
131 |
+
else {
|
132 |
+
Mage::log(' BV - Purchase feed disabled for store: ' . $store->getCode(), Zend_Log::INFO);
|
133 |
+
}
|
134 |
+
}
|
135 |
+
catch (Exception $e) {
|
136 |
+
Mage::log(' BV - Failed to export daily purchase feed for store: ' . $store->getCode(), Zend_Log::ERR);
|
137 |
+
Mage::log(' BV - Error message: ' . $e->getMessage(), Zend_Log::ERR);
|
138 |
+
Mage::logException($e);
|
139 |
+
// Continue processing other stores
|
140 |
+
}
|
141 |
+
}
|
142 |
+
}
|
143 |
+
|
144 |
+
/**
|
145 |
+
* @param Mage_Core_Model_Website $website
|
146 |
+
*/
|
147 |
+
public function exportPurchaseFeedForWebsite(Mage_Core_Model_Website $website)
|
148 |
+
{
|
149 |
+
// Get ref to BV helper
|
150 |
+
/* @var $bvHelper Bazaarvoice_Connector_Helper_Data */
|
151 |
+
$bvHelper = Mage::helper('bazaarvoice');
|
152 |
+
|
153 |
+
// Build purchase export file path and name
|
154 |
+
$purchaseFeedFilePath = Mage::getBaseDir("var") . DS . 'export' . DS . 'bvfeeds';
|
155 |
+
$purchaseFeedFileName = 'purchaseFeed-website-' . $website->getId() . '-' . date('U') . '.xml';
|
156 |
+
|
157 |
+
// Make sure that the directory we want to write to exists.
|
158 |
+
$ioObject = new Varien_Io_File();
|
159 |
+
try {
|
160 |
+
$ioObject->open(array('path' => $purchaseFeedFilePath));
|
161 |
+
}
|
162 |
+
catch (Exception $e) {
|
163 |
+
$ioObject->mkdir($purchaseFeedFilePath, 0777, true);
|
164 |
+
$ioObject->open(array('path' => $purchaseFeedFilePath));
|
165 |
+
}
|
166 |
+
|
167 |
+
if ($ioObject->streamOpen($purchaseFeedFileName)) {
|
168 |
+
|
169 |
+
$ioObject->streamWrite("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Feed xmlns=\"http://www.bazaarvoice.com/xs/PRR/PostPurchaseFeed/4.9\">\n");
|
170 |
+
|
171 |
+
Mage::log(' BV - processing all orders');
|
172 |
+
$numOrdersExported = $this->processOrdersForWebsite($ioObject, $website);
|
173 |
+
Mage::log(' BV - completed processing all orders');
|
174 |
+
|
175 |
+
$ioObject->streamWrite("</Feed>\n");
|
176 |
+
$ioObject->streamClose();
|
177 |
+
|
178 |
+
// Don't bother uploading if there are no orders in the feed
|
179 |
+
$upload = false;
|
180 |
+
if ($numOrdersExported > 0) {
|
181 |
+
/*
|
182 |
+
* Hard code path and file name
|
183 |
+
* Former config setting defaults:
|
184 |
+
* <ExportPath>/ppe/inbox</ExportPath>
|
185 |
+
* <ExportFileName>bazaarvoice-order-data.xml</ExportFileName>
|
186 |
+
*/
|
187 |
+
$destinationFile = '/ppe/inbox/bazaarvoice-order-data-' . date('U') . '.xml';
|
188 |
+
$sourceFile = $purchaseFeedFilePath . DS . $purchaseFeedFileName;
|
189 |
+
|
190 |
+
$upload = $bvHelper->uploadFile($sourceFile, $destinationFile, $website->getDefaultStore());
|
191 |
+
}
|
192 |
+
|
193 |
+
if (!$upload) {
|
194 |
+
Mage::log(' Bazaarvoice FTP upload failed! [filename = ' . $purchaseFeedFileName . ']');
|
195 |
+
}
|
196 |
+
else {
|
197 |
+
Mage::log(' Bazaarvoice FTP upload success! [filename = ' . $purchaseFeedFileName . ']');
|
198 |
+
$ioObject->rm($purchaseFeedFileName);
|
199 |
+
}
|
200 |
+
|
201 |
+
}
|
202 |
+
}
|
203 |
+
|
204 |
+
/**
|
205 |
+
*
|
206 |
+
* @param Mage_Core_Model_Store_Group $group Store Group
|
207 |
+
*/
|
208 |
+
public function exportPurchaseFeedForStoreGroup(Mage_Core_Model_Store_Group $group)
|
209 |
+
{
|
210 |
+
// Get ref to BV helper
|
211 |
+
/* @var $bvHelper Bazaarvoice_Connector_Helper_Data */
|
212 |
+
$bvHelper = Mage::helper('bazaarvoice');
|
213 |
+
|
214 |
+
// Build purchase export file path and name
|
215 |
+
$purchaseFeedFilePath = Mage::getBaseDir("var") . DS . 'export' . DS . 'bvfeeds';
|
216 |
+
$purchaseFeedFileName = 'purchaseFeed-group-' . $group->getId() . '-' . date('U') . '.xml';
|
217 |
+
|
218 |
+
// Make sure that the directory we want to write to exists.
|
219 |
+
$ioObject = new Varien_Io_File();
|
220 |
+
try {
|
221 |
+
$ioObject->open(array('path' => $purchaseFeedFilePath));
|
222 |
+
}
|
223 |
+
catch (Exception $e) {
|
224 |
+
$ioObject->mkdir($purchaseFeedFilePath, 0777, true);
|
225 |
+
$ioObject->open(array('path' => $purchaseFeedFilePath));
|
226 |
+
}
|
227 |
+
|
228 |
+
if ($ioObject->streamOpen($purchaseFeedFileName)) {
|
229 |
+
|
230 |
+
$ioObject->streamWrite("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Feed xmlns=\"http://www.bazaarvoice.com/xs/PRR/PostPurchaseFeed/4.9\">\n");
|
231 |
+
|
232 |
+
Mage::log(' BV - processing all orders');
|
233 |
+
$numOrdersExported = $this->processOrdersForGroup($ioObject, $group);
|
234 |
+
Mage::log(' BV - completed processing all orders');
|
235 |
+
|
236 |
+
$ioObject->streamWrite("</Feed>\n");
|
237 |
+
$ioObject->streamClose();
|
238 |
+
|
239 |
+
// Don't bother uploading if there are no orders in the feed
|
240 |
+
$upload = false;
|
241 |
+
if ($numOrdersExported > 0) {
|
242 |
+
/*
|
243 |
+
* Hard code path and file name
|
244 |
+
* Former config setting defaults:
|
245 |
+
* <ExportPath>/ppe/inbox</ExportPath>
|
246 |
+
* <ExportFileName>bazaarvoice-order-data.xml</ExportFileName>
|
247 |
+
*/
|
248 |
+
$destinationFile = '/ppe/inbox/bazaarvoice-order-data-' . date('U') . '.xml';
|
249 |
+
$sourceFile = $purchaseFeedFilePath . DS . $purchaseFeedFileName;
|
250 |
+
|
251 |
+
$upload = $bvHelper->uploadFile($sourceFile, $destinationFile, $group->getDefaultStore());
|
252 |
+
}
|
253 |
+
|
254 |
+
if (!$upload) {
|
255 |
+
Mage::log(' Bazaarvoice FTP upload failed! [filename = ' . $purchaseFeedFileName . ']');
|
256 |
+
}
|
257 |
+
else {
|
258 |
+
Mage::log(' Bazaarvoice FTP upload success! [filename = ' . $purchaseFeedFileName . ']');
|
259 |
+
$ioObject->rm($purchaseFeedFileName);
|
260 |
+
}
|
261 |
+
|
262 |
+
}
|
263 |
+
}
|
264 |
+
|
265 |
+
/**
|
266 |
+
* @param Mage_Core_Model_Store $store
|
267 |
+
*/
|
268 |
+
public function exportPurchaseFeedForStore(Mage_Core_Model_Store $store)
|
269 |
+
{
|
270 |
+
// Get ref to BV helper
|
271 |
+
/* @var $bvHelper Bazaarvoice_Connector_Helper_Data */
|
272 |
+
$bvHelper = Mage::helper('bazaarvoice');
|
273 |
+
|
274 |
+
// Build purchase export file path and name
|
275 |
+
$purchaseFeedFilePath = Mage::getBaseDir('var') . DS . 'export' . DS . 'bvfeeds';
|
276 |
+
$purchaseFeedFileName = 'purchaseFeed-store-' . $store->getId() . '-' . date('U') . '.xml';
|
277 |
+
|
278 |
+
// Make sure that the directory we want to write to exists.
|
279 |
+
$ioObject = new Varien_Io_File();
|
280 |
+
try {
|
281 |
+
$ioObject->open(array('path' => $purchaseFeedFilePath));
|
282 |
+
}
|
283 |
+
catch (Exception $e) {
|
284 |
+
$ioObject->mkdir($purchaseFeedFilePath, 0777, true);
|
285 |
+
$ioObject->open(array('path' => $purchaseFeedFilePath));
|
286 |
+
}
|
287 |
+
|
288 |
+
if ($ioObject->streamOpen($purchaseFeedFileName)) {
|
289 |
+
|
290 |
+
$ioObject->streamWrite("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Feed xmlns=\"http://www.bazaarvoice.com/xs/PRR/PostPurchaseFeed/4.9\">\n");
|
291 |
+
|
292 |
+
Mage::log(" BV - processing all orders");
|
293 |
+
$numOrdersExported = $this->processOrdersForStore($ioObject, $store);
|
294 |
+
Mage::log(" BV - completed processing all orders");
|
295 |
+
|
296 |
+
$ioObject->streamWrite("</Feed>\n");
|
297 |
+
$ioObject->streamClose();
|
298 |
+
|
299 |
+
// Don't bother uploading if there are no orders in the feed
|
300 |
+
$upload = false;
|
301 |
+
if ($numOrdersExported > 0) {
|
302 |
+
/*
|
303 |
+
* Hard code path and file name
|
304 |
+
* Former config setting defaults:
|
305 |
+
* <ExportPath>/ppe/inbox</ExportPath>
|
306 |
+
* <ExportFileName>bazaarvoice-order-data.xml</ExportFileName>
|
307 |
+
*/
|
308 |
+
$destinationFile = '/ppe/inbox/bazaarvoice-order-data-' . date('U') . '.xml';
|
309 |
+
$sourceFile = $purchaseFeedFilePath . DS . $purchaseFeedFileName;
|
310 |
+
|
311 |
+
$upload = $bvHelper->uploadFile($sourceFile, $destinationFile, $store);
|
312 |
+
}
|
313 |
+
|
314 |
+
if (!$upload) {
|
315 |
+
Mage::log(' Bazaarvoice FTP upload failed! [filename = ' . $purchaseFeedFileName . ']');
|
316 |
+
}
|
317 |
+
else {
|
318 |
+
Mage::log(' Bazaarvoice FTP upload success! [filename = ' . $purchaseFeedFileName . ']');
|
319 |
+
$ioObject->rm($purchaseFeedFileName);
|
320 |
+
}
|
321 |
+
|
322 |
+
}
|
323 |
+
}
|
324 |
+
|
325 |
+
/**
|
326 |
+
* @param Varien_Io_File $ioObject
|
327 |
+
* @param Mage_Core_Model_Website $website
|
328 |
+
* @return int
|
329 |
+
*/
|
330 |
+
private function processOrdersForWebsite(Varien_Io_File $ioObject, Mage_Core_Model_Website $website)
|
331 |
+
{
|
332 |
+
// Get a collection of all the orders
|
333 |
+
$orders = Mage::getModel('sales/order')->getCollection();
|
334 |
+
|
335 |
+
// Filter the returned orders to minimize processing as much as possible. More available operations in method _getConditionSql in Varien_Data_Collection_Db.
|
336 |
+
// Add filter to limit orders to this store group
|
337 |
+
// Join to core_store table and grab website_id field
|
338 |
+
$orders->getSelect()
|
339 |
+
->joinLeft('core_store', 'main_table.store_id = core_store.store_id', 'core_store.website_id')
|
340 |
+
->where('core_store.website_id = ' . $website->getId());
|
341 |
+
// Status is 'complete' or 'closed'
|
342 |
+
$orders->addFieldToFilter('status', array(
|
343 |
+
'in' => array(
|
344 |
+
'complete',
|
345 |
+
'closed'
|
346 |
+
)
|
347 |
+
));
|
348 |
+
// Only orders created within our look-back window
|
349 |
+
$orders->addFieldToFilter('created_at', array('gteq' => $this->getNumDaysLookbackStartDate()));
|
350 |
+
// Exclude orders that have been previously sent in a feed
|
351 |
+
$orders->addFieldToFilter(self::ALREADY_SENT_IN_FEED_FLAG, array('null' => 'null')); // adds an 'IS NULL' filter to the BV flag column
|
352 |
+
|
353 |
+
// Write orders to file
|
354 |
+
$numOrdersExported = $this->writeOrdersToFile($ioObject, $orders);
|
355 |
+
|
356 |
+
return $numOrdersExported;
|
357 |
+
}
|
358 |
+
|
359 |
+
/**
|
360 |
+
* @param Varien_Io_File $ioObject
|
361 |
+
* @param Mage_Core_Model_Store_Group $group
|
362 |
+
* @return int
|
363 |
+
*/
|
364 |
+
private function processOrdersForGroup(Varien_Io_File $ioObject, Mage_Core_Model_Store_Group $group)
|
365 |
+
{
|
366 |
+
// Get a collection of all the orders
|
367 |
+
$orders = Mage::getModel('sales/order')->getCollection();
|
368 |
+
|
369 |
+
// Filter the returned orders to minimize processing as much as possible. More available operations in method _getConditionSql in Varien_Data_Collection_Db.
|
370 |
+
// Add filter to limit orders to this store group
|
371 |
+
// Join to core_store table and grab group_id field
|
372 |
+
$orders->getSelect()
|
373 |
+
->joinLeft('core_store', 'main_table.store_id = core_store.store_id', 'core_store.group_id')
|
374 |
+
->where('core_store.group_id = ' . $group->getId());
|
375 |
+
// Status is 'complete' or 'closed'
|
376 |
+
$orders->addFieldToFilter('status', array(
|
377 |
+
'in' => array(
|
378 |
+
'complete',
|
379 |
+
'closed'
|
380 |
+
)
|
381 |
+
));
|
382 |
+
// Only orders created within our look-back window
|
383 |
+
$orders->addFieldToFilter('created_at', array('gteq' => $this->getNumDaysLookbackStartDate()));
|
384 |
+
// Exclude orders that have been previously sent in a feed
|
385 |
+
$orders->addFieldToFilter(self::ALREADY_SENT_IN_FEED_FLAG, array('null' => 'null')); // adds an 'IS NULL' filter to the BV flag column
|
386 |
+
|
387 |
+
// Write orders to file
|
388 |
+
$numOrdersExported = $this->writeOrdersToFile($ioObject, $orders);
|
389 |
+
|
390 |
+
return $numOrdersExported;
|
391 |
+
}
|
392 |
+
|
393 |
+
/**
|
394 |
+
* @param Varien_Io_File $ioObject
|
395 |
+
* @param Mage_Core_Model_Store $store
|
396 |
+
* @return int
|
397 |
+
*/
|
398 |
+
private function processOrdersForStore(Varien_Io_File $ioObject, Mage_Core_Model_Store $store)
|
399 |
+
{
|
400 |
+
// Get a collection of all the orders
|
401 |
+
$orders = Mage::getModel('sales/order')->getCollection();
|
402 |
+
|
403 |
+
// Filter the returned orders to minimize processing as much as possible. More available operations in method _getConditionSql in Varien_Data_Collection_Db.
|
404 |
+
// Add filter to limit orders to this store
|
405 |
+
$orders->addFieldToFilter('store_id', $store->getId());
|
406 |
+
// Status is 'complete' or 'closed'
|
407 |
+
$orders->addFieldToFilter('status', array(
|
408 |
+
'in' => array(
|
409 |
+
'complete',
|
410 |
+
'closed'
|
411 |
+
)
|
412 |
+
));
|
413 |
+
// Only orders created within our look-back window
|
414 |
+
$orders->addFieldToFilter('created_at', array('gteq' => $this->getNumDaysLookbackStartDate()));
|
415 |
+
// Exclude orders that have been previously sent in a feed
|
416 |
+
$orders->addFieldToFilter(self::ALREADY_SENT_IN_FEED_FLAG, array('null' => 'null')); // adds an 'IS NULL' filter to the BV flag column
|
417 |
+
|
418 |
+
// Write orders to file
|
419 |
+
$numOrdersExported = $this->writeOrdersToFile($ioObject, $orders);
|
420 |
+
|
421 |
+
return $numOrdersExported;
|
422 |
+
}
|
423 |
+
|
424 |
+
/**
|
425 |
+
* @param Varien_Io_File $ioObject
|
426 |
+
* @param $orders
|
427 |
+
* @return int
|
428 |
+
*/
|
429 |
+
private function writeOrdersToFile(Varien_Io_File $ioObject, $orders)
|
430 |
+
{
|
431 |
+
// Get ref to BV helper
|
432 |
+
/* @var $bvHelper Bazaarvoice_Connector_Helper_Data */
|
433 |
+
$bvHelper = Mage::helper('bazaarvoice');
|
434 |
+
|
435 |
+
// Initialize references to the object model accessors
|
436 |
+
$orderModel = Mage::getModel('sales/order');
|
437 |
+
|
438 |
+
// Gather settings for how this feed should be generated
|
439 |
+
$triggeringEvent = Mage::getStoreConfig('bazaarvoice/feeds/triggering_event') ===
|
440 |
+
Bazaarvoice_Connector_Model_Source_TriggeringEvent::SHIPPING ? self::TRIGGER_EVENT_SHIP : self::TRIGGER_EVENT_PURCHASE;
|
441 |
+
// Hard code former settings
|
442 |
+
$delayDaysSinceEvent = 1;
|
443 |
+
Mage::log(" BV - Config {triggering_event: " . $triggeringEvent
|
444 |
+
. ", NumDaysLookback: " . self::NUM_DAYS_LOOKBACK
|
445 |
+
. ", NumDaysLookbackStartDate: " . $this->getNumDaysLookbackStartDate()
|
446 |
+
. ", DelayDaysSinceEvent: " . $delayDaysSinceEvent
|
447 |
+
. ', DelayDaysThreshold: ' . date('c', $this->getDelayDaysThresholdTimestamp($delayDaysSinceEvent)) . '}');
|
448 |
+
|
449 |
+
$numOrdersExported = 0; // Keep track of how many orders we include in the feed
|
450 |
+
|
451 |
+
foreach ($orders->getAllIds() as $orderId) {
|
452 |
+
|
453 |
+
/* @var $order Mage_Sales_Model_Order */
|
454 |
+
$order = $orderModel->load($orderId);
|
455 |
+
$store = $order->getStore();
|
456 |
+
|
457 |
+
if (!$this->shouldIncludeOrder($order, $triggeringEvent, $delayDaysSinceEvent)) {
|
458 |
+
continue;
|
459 |
+
}
|
460 |
+
|
461 |
+
$numOrdersExported++;
|
462 |
+
|
463 |
+
$ioObject->streamWrite("<Interaction>\n");
|
464 |
+
$ioObject->streamWrite(' <EmailAddress>' . $order->getCustomerEmail() . "</EmailAddress>\n");
|
465 |
+
$ioObject->streamWrite(' <Locale>' . $store->getConfig('bazaarvoice/general/locale') . "</Locale>\n");
|
466 |
+
$ioObject->streamWrite(' <UserName>' . $order->getCustomerName() . "</UserName>\n");
|
467 |
+
$ioObject->streamWrite(' <UserID>' . $order->getCustomerId() . "</UserID>\n");
|
468 |
+
$ioObject->streamWrite(' <TransactionDate>' . $this->getTriggeringEventDate($order, $triggeringEvent) .
|
469 |
+
"</TransactionDate>\n");
|
470 |
+
$ioObject->streamWrite(" <Products>\n");
|
471 |
+
/* @var $item Mage_Sales_Model_Order_Item */
|
472 |
+
foreach ($order->getAllVisibleItems() as $item) {
|
473 |
+
$product = $bvHelper->getReviewableProductFromOrderItem($item);
|
474 |
+
if (!is_null($product)) {
|
475 |
+
$ioObject->streamWrite(" <Product>\n");
|
476 |
+
$ioObject->streamWrite(' <ExternalId>' . $bvHelper->getProductId($product) .
|
477 |
+
"</ExternalId>\n");
|
478 |
+
$ioObject->streamWrite(' <Name>' . htmlspecialchars($product->getName(), ENT_QUOTES, 'UTF-8') .
|
479 |
+
"</Name>\n");
|
480 |
+
$ioObject->streamWrite(' <ImageUrl>' . $product->getImageUrl() . "</ImageUrl>\n");
|
481 |
+
$ioObject->streamWrite(' <Price>' . number_format((float)$item->getOriginalPrice(), 2) . "</Price>\n");
|
482 |
+
$ioObject->streamWrite(" </Product>\n");
|
483 |
+
}
|
484 |
+
}
|
485 |
+
$ioObject->streamWrite(" </Products>\n");
|
486 |
+
$ioObject->streamWrite("</Interaction>\n");
|
487 |
+
|
488 |
+
$order->setData(self::ALREADY_SENT_IN_FEED_FLAG, 1);
|
489 |
+
$order->save();
|
490 |
+
$order->reset(); // Forces a reload of various collections that the object caches internally so that the next time we load from the orderModel, we'll get a completely new object.
|
491 |
+
|
492 |
+
}
|
493 |
+
|
494 |
+
return $numOrdersExported;
|
495 |
+
}
|
496 |
+
|
497 |
+
private function orderToString(Mage_Sales_Model_Order $order)
|
498 |
+
{
|
499 |
+
return "\nOrder {Id: " . $order->getId()
|
500 |
+
. "\n\tCustomerId: " . $order->getCustomerId()
|
501 |
+
. "\n\tStatus: " . $order->getStatus()
|
502 |
+
. "\n\tState: " . $order->getState()
|
503 |
+
. "\n\tDate: " . date('c', strtotime($order->getCreatedAtDate()))
|
504 |
+
. "\n\tHasShipped: " . $this->hasOrderCompletelyShipped($order)
|
505 |
+
. "\n\tLatestShipmentDate: " . date('c', $this->getLatestShipmentDate($order))
|
506 |
+
. "\n\tNumItems: " . count($order->getAllItems())
|
507 |
+
. "\n\tSentInBVPPEFeed: " . $order->getData(self::ALREADY_SENT_IN_FEED_FLAG)
|
508 |
+
// . "\n\tCustomerEmail: " . $order->getCustomerEmail() // Don't put CustomerEmail in the logs - could be considered PII
|
509 |
+
. "\n}";
|
510 |
+
}
|
511 |
+
|
512 |
+
private function getTriggeringEventDate(Mage_Sales_Model_Order $order, $triggeringEvent)
|
513 |
+
{
|
514 |
+
$timestamp = strtotime($order->getCreatedAtDate());
|
515 |
+
|
516 |
+
if ($triggeringEvent === self::TRIGGER_EVENT_SHIP) {
|
517 |
+
$timestamp = $this->getLatestShipmentDate($order);
|
518 |
+
}
|
519 |
+
|
520 |
+
return date('c', $timestamp);
|
521 |
+
}
|
522 |
+
|
523 |
+
private function getNumDaysLookbackStartDate()
|
524 |
+
{
|
525 |
+
return date('Y-m-d', strtotime(date('Y-m-d', time()) . ' -' . self::NUM_DAYS_LOOKBACK . ' days'));
|
526 |
+
}
|
527 |
+
|
528 |
+
private function getDelayDaysThresholdTimestamp($delayDaysSinceEvent)
|
529 |
+
{
|
530 |
+
return time() - (24 * 60 * 60 * $delayDaysSinceEvent);
|
531 |
+
}
|
532 |
+
|
533 |
+
private function shouldIncludeOrder(Mage_Sales_Model_Order $order, $triggeringEvent, $delayDaysSinceEvent)
|
534 |
+
{
|
535 |
+
// Have we already included this order in a previous feed?
|
536 |
+
if ($order->getData(self::ALREADY_SENT_IN_FEED_FLAG) === '1') {
|
537 |
+
Mage::log(' BV - Skipping Order. Already included in previous feed. ' . $this->orderToString($order));
|
538 |
+
return false;
|
539 |
+
}
|
540 |
+
|
541 |
+
// Is the order canceled?
|
542 |
+
if ($order->isCanceled()) {
|
543 |
+
Mage::log(' BV - Skipping Order. Canceled state. ' . $this->orderToString($order));
|
544 |
+
return false;
|
545 |
+
}
|
546 |
+
|
547 |
+
// Ensure that we can get the store for the order
|
548 |
+
$store = $order->getStore();
|
549 |
+
if (is_null($store)) {
|
550 |
+
Mage::log(' BV - Skipping Order. Could not find store for order. ' . $this->orderToString($order));
|
551 |
+
return false;
|
552 |
+
}
|
553 |
+
|
554 |
+
$thresholdTimestamp = $this->getDelayDaysThresholdTimestamp($delayDaysSinceEvent);
|
555 |
+
|
556 |
+
if ($triggeringEvent === self::TRIGGER_EVENT_SHIP) {
|
557 |
+
// We need to see if this order is completely shipped, and if so, is the latest item ship date outside of the delay period.
|
558 |
+
|
559 |
+
// Is the order completely shipped?
|
560 |
+
if (!$this->hasOrderCompletelyShipped($order)) {
|
561 |
+
Mage::log(' BV - Skipping Order. Not completely shipped. ' . $this->orderToString($order));
|
562 |
+
return false;
|
563 |
+
}
|
564 |
+
|
565 |
+
// Are we outside of the delay period
|
566 |
+
$latestItemShipDateTimestamp = $this->getLatestShipmentDate($order);
|
567 |
+
if ($latestItemShipDateTimestamp > $thresholdTimestamp) {
|
568 |
+
// Latest ship date for the fully shipped order is still within the delay period
|
569 |
+
Mage::log(' BV - Skipping Order. Ship date not outside the threshold of ' . date('c', $thresholdTimestamp) . '. ' .
|
570 |
+
$this->orderToString($order));
|
571 |
+
return false;
|
572 |
+
}
|
573 |
+
}
|
574 |
+
else {
|
575 |
+
if ($triggeringEvent === self::TRIGGER_EVENT_PURCHASE) {
|
576 |
+
// We need to see if the order placement timestamp of this order is outside of the delay period
|
577 |
+
$orderPlacementTimestamp = strtotime($order->getCreatedAtDate());
|
578 |
+
if ($orderPlacementTimestamp > $thresholdTimestamp) {
|
579 |
+
// Order placement date is still within the delay period
|
580 |
+
Mage::log(' BV - Skipping Order. Order date not outside the threshold of ' . date('c', $thresholdTimestamp) .
|
581 |
+
'. ' .
|
582 |
+
$this->orderToString($order));
|
583 |
+
return false;
|
584 |
+
}
|
585 |
+
}
|
586 |
+
}
|
587 |
+
|
588 |
+
|
589 |
+
// Finally, ensure we have everything on this order that would be needed.
|
590 |
+
|
591 |
+
// Do we have what basically looks like a legit email address?
|
592 |
+
if (!preg_match('/@/', $order->getCustomerEmail())) {
|
593 |
+
Mage::log(' BV - Skipping Order. No valid email address. ' . $this->orderToString($order));
|
594 |
+
return false;
|
595 |
+
}
|
596 |
+
|
597 |
+
// Does the order have any items?
|
598 |
+
if (count($order->getAllItems()) < 1) {
|
599 |
+
Mage::log(' BV - Skipping Order. No items in this order. ' . $this->orderToString($order));
|
600 |
+
return false;
|
601 |
+
}
|
602 |
+
|
603 |
+
|
604 |
+
if (self::DEBUG_OUTPUT) {
|
605 |
+
Mage::log(' BV - Including Order. ' . $this->orderToString($order));
|
606 |
+
}
|
607 |
+
return true;
|
608 |
+
}
|
609 |
+
|
610 |
+
private function hasOrderCompletelyShipped(Mage_Sales_Model_Order $order)
|
611 |
+
{
|
612 |
+
$hasOrderCompletelyShipped = true;
|
613 |
+
$items = $order->getAllItems();
|
614 |
+
/* @var $item Mage_Sales_Model_Order_Item */
|
615 |
+
foreach ($items as $item) {
|
616 |
+
// See /var/www/magento/app/code/core/Mage/Sales/Model/Order/Item.php
|
617 |
+
if ($item->getQtyToShip() > 0 && !$item->getIsVirtual() && !$item->getLockedDoShip()) {
|
618 |
+
// This item still has qty that needs to ship
|
619 |
+
$hasOrderCompletelyShipped = false;
|
620 |
+
}
|
621 |
+
}
|
622 |
+
return $hasOrderCompletelyShipped;
|
623 |
+
}
|
624 |
+
|
625 |
+
private function getLatestShipmentDate(Mage_Sales_Model_Order $order)
|
626 |
+
{
|
627 |
+
$latestShipmentTimestamp = 0;
|
628 |
+
|
629 |
+
$shipments = $order->getShipmentsCollection();
|
630 |
+
/* @var $shipment Mage_Sales_Model_Order_Shipment */
|
631 |
+
foreach ($shipments as $shipment) {
|
632 |
+
$latestShipmentTimestamp = max(strtotime($shipment->getCreatedAtDate()), $latestShipmentTimestamp);
|
633 |
+
}
|
634 |
+
|
635 |
+
return $latestShipmentTimestamp; // This should be an int timestamp of num seconds since epoch
|
636 |
+
}
|
637 |
+
|
638 |
+
}
|
639 |
+
|
app/code/local/Bazaarvoice/Connector/Model/Mysql4/Setup.php
ADDED
@@ -0,0 +1,11 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This class can be used to customize any behavior during the MySQL installation or upgrade scripts between versions
|
4 |
+
* of the Bazaarvoice Magento extension.
|
5 |
+
*/
|
6 |
+
class Bazaarvoice_Connector_Model_Mysql4_Setup extends Mage_Sales_Model_Mysql4_Setup
|
7 |
+
{
|
8 |
+
|
9 |
+
|
10 |
+
}
|
11 |
+
|
app/code/local/Bazaarvoice/Connector/Model/ProductFeed/Brand.php
ADDED
@@ -0,0 +1,191 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @author Bazaarvoice, Inc.
|
4 |
+
*/
|
5 |
+
class Bazaarvoice_Connector_Model_ProductFeed_Brand extends Mage_Core_Model_Abstract
|
6 |
+
{
|
7 |
+
|
8 |
+
/**
|
9 |
+
* @param Varien_Io_File $ioObject File object for feed file
|
10 |
+
* @param Mage_Core_Model_Website $website
|
11 |
+
*/
|
12 |
+
public function processBrandsForWebsite(Varien_Io_File $ioObject, Mage_Core_Model_Website $website)
|
13 |
+
{
|
14 |
+
// Get default store for website
|
15 |
+
$defaultStore = $website->getDefaultGroup()->getDefaultStore();
|
16 |
+
// Lookup default locale code
|
17 |
+
$defaultLocaleCode = Mage::getStoreConfig('bazaarvoice/general/locale', $defaultStore->getId());
|
18 |
+
// Check localeCode
|
19 |
+
if (!strlen($defaultLocaleCode)) {
|
20 |
+
Mage::throwException('Invalid locale code configured for store: ' . $defaultStore->getCode());
|
21 |
+
}
|
22 |
+
|
23 |
+
// Lookup the configured attribute code for "Brand"
|
24 |
+
$attributeCode = Mage::getStoreConfig('bazaarvoice/bv_config/product_feed_brand_attribute_code', $defaultStore->getId());
|
25 |
+
// If there is no attribute code for default store, then bail
|
26 |
+
if(!strlen(trim($attributeCode))) {
|
27 |
+
return;
|
28 |
+
}
|
29 |
+
|
30 |
+
// Look up options for each store
|
31 |
+
$optionsByLocale = array();
|
32 |
+
/** @var Mage_Core_Model_Store $store */
|
33 |
+
foreach ($website->getStores() as $store) {
|
34 |
+
// Get store locale
|
35 |
+
$localeCode = Mage::getStoreConfig('bazaarvoice/general/locale', $store->getId());
|
36 |
+
// Check localeCode
|
37 |
+
if (!strlen($localeCode)) {
|
38 |
+
Mage::throwException('Invalid locale code configured for store: ' . $store->getCode());
|
39 |
+
}
|
40 |
+
// Save options mapped to localeCode
|
41 |
+
$optionsByLocale[$localeCode] = $this->getOptionsForStore($store);
|
42 |
+
}
|
43 |
+
|
44 |
+
// Now process brands in multi-store fashion
|
45 |
+
$this->processBrandsMultiStore($ioObject, $defaultLocaleCode, $optionsByLocale);
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* @param Varien_Io_File $ioObject File object for feed file
|
50 |
+
* @param Mage_Core_Model_Store_Group $group
|
51 |
+
*/
|
52 |
+
public function processBrandsForGroup(Varien_Io_File $ioObject, Mage_Core_Model_Store_Group $group)
|
53 |
+
{
|
54 |
+
// Get default store for group
|
55 |
+
$defaultStore = $group->getDefaultStore();
|
56 |
+
// Lookup default locale code
|
57 |
+
$defaultLocaleCode = Mage::getStoreConfig('bazaarvoice/general/locale', $defaultStore->getId());
|
58 |
+
// Check localeCode
|
59 |
+
if (!strlen($defaultLocaleCode)) {
|
60 |
+
Mage::throwException('Invalid locale code configured for store: ' . $defaultStore->getCode());
|
61 |
+
}
|
62 |
+
|
63 |
+
// Lookup the configured attribute code for "Brand"
|
64 |
+
$attributeCode = Mage::getStoreConfig('bazaarvoice/bv_config/product_feed_brand_attribute_code', $defaultStore->getId());
|
65 |
+
// If there is no attribute code for default store, then bail
|
66 |
+
if(!strlen(trim($attributeCode))) {
|
67 |
+
return;
|
68 |
+
}
|
69 |
+
|
70 |
+
// Look up options for each store
|
71 |
+
$optionsByLocale = array();
|
72 |
+
/** @var Mage_Core_Model_Store $store */
|
73 |
+
foreach ($group->getStores() as $store) {
|
74 |
+
// Get store locale
|
75 |
+
$localeCode = Mage::getStoreConfig('bazaarvoice/general/locale', $store->getId());
|
76 |
+
// Check localeCode
|
77 |
+
if (!strlen($localeCode)) {
|
78 |
+
Mage::throwException('Invalid locale code configured for store: ' . $store->getCode());
|
79 |
+
}
|
80 |
+
// Save options mapped to localeCode
|
81 |
+
$optionsByLocale[$localeCode] = $this->getOptionsForStore($store);
|
82 |
+
}
|
83 |
+
|
84 |
+
// Now process brands in multi-store fashion
|
85 |
+
$this->processBrandsMultiStore($ioObject, $defaultLocaleCode, $optionsByLocale);
|
86 |
+
}
|
87 |
+
|
88 |
+
/**
|
89 |
+
* @param Varien_Io_File $ioObject File object for feed file
|
90 |
+
* @param Mage_Core_Model_Store $store
|
91 |
+
*/
|
92 |
+
public function processBrandsForStore(Varien_Io_File $ioObject, Mage_Core_Model_Store $store)
|
93 |
+
{
|
94 |
+
// Lookup the configured attribute code for "Brand"
|
95 |
+
$attributeCode = Mage::getStoreConfig('bazaarvoice/bv_config/product_feed_brand_attribute_code', $store->getId());
|
96 |
+
// If there is no attribute code for store, then bail
|
97 |
+
if(!strlen(trim($attributeCode))) {
|
98 |
+
return;
|
99 |
+
}
|
100 |
+
|
101 |
+
// Lookup up brand names
|
102 |
+
$attributeOptions = $this->getOptionsForStore($store);
|
103 |
+
// Output tag only if more than 1 brand
|
104 |
+
if (count($attributeOptions) > 0) {
|
105 |
+
$ioObject->streamWrite("<Brands>\n");
|
106 |
+
}
|
107 |
+
// Iterate brands and write each to file
|
108 |
+
foreach($attributeOptions as $optionId => $optionValue) {
|
109 |
+
$this->writeBrand($ioObject, $optionId, $optionValue);
|
110 |
+
}
|
111 |
+
if (count($attributeOptions) > 0) {
|
112 |
+
$ioObject->streamWrite("</Brands>\n");
|
113 |
+
}
|
114 |
+
}
|
115 |
+
|
116 |
+
protected function processBrandsMultiStore($ioObject, $defaultLocaleCode, $optionsByLocale)
|
117 |
+
{
|
118 |
+
// Recombine multi-dimensional array so its grouped by option id
|
119 |
+
$allOptions = array();
|
120 |
+
foreach($optionsByLocale as $localeCode => $options) {
|
121 |
+
// Check if this store is default
|
122 |
+
if($localeCode == $defaultLocaleCode) {
|
123 |
+
$defaultOptions = $options;
|
124 |
+
}
|
125 |
+
// Add this store's options to main array
|
126 |
+
foreach($options as $optionId => $optionValue) {
|
127 |
+
if(!isset($allOptions[$optionId])) {
|
128 |
+
$allOptions[$optionId] = array();
|
129 |
+
}
|
130 |
+
$allOptions[$optionId][$localeCode] = $optionValue;
|
131 |
+
}
|
132 |
+
}
|
133 |
+
// Output tag only if more than 1 brand
|
134 |
+
if (count($allOptions) > 0) {
|
135 |
+
$ioObject->streamWrite("<Brands>\n");
|
136 |
+
}
|
137 |
+
// Now iterate through all brands and write out
|
138 |
+
foreach($allOptions as $optionId => $localeValues) {
|
139 |
+
$this->writeBrandMultiLocale($ioObject, $optionId, $defaultOptions[$optionId], $localeValues);
|
140 |
+
}
|
141 |
+
if (count($allOptions) > 0) {
|
142 |
+
$ioObject->streamWrite("</Brands>\n");
|
143 |
+
}
|
144 |
+
}
|
145 |
+
|
146 |
+
protected function getOptionsForStore($store)
|
147 |
+
{
|
148 |
+
// Lookup the configured attribute code for "Brand"
|
149 |
+
$attributeCode = Mage::getStoreConfig('bazaarvoice/bv_config/product_feed_brand_attribute_code', $store->getId());
|
150 |
+
// Lookup the attribute options for this store
|
151 |
+
/** @var Mage_Catalog_Model_Resource_Eav_Attribute $attribute */
|
152 |
+
$attribute = Mage::getModel('catalog/resource_eav_attribute')->load($attributeCode, 'attribute_code');
|
153 |
+
$attribute->setStoreId($store->getId());
|
154 |
+
$attributeOptions = $attribute->getSource()->getAllOptions(false);
|
155 |
+
// Reformat array
|
156 |
+
$processedOptions = array();
|
157 |
+
foreach ($attributeOptions as $attributeOption) {
|
158 |
+
$processedOptions[$attributeOption['value']] = $attributeOption['label'];
|
159 |
+
}
|
160 |
+
|
161 |
+
return $processedOptions;
|
162 |
+
}
|
163 |
+
|
164 |
+
protected function writeBrand(Varien_Io_File $ioObject, $brandExternalId, $brandName)
|
165 |
+
{
|
166 |
+
$ioObject->streamWrite(
|
167 |
+
"<Brand>\n" .
|
168 |
+
" <ExternalId>" . $brandExternalId . "</ExternalId>\n" .
|
169 |
+
" <Name><![CDATA[" . $brandName . "]]></Name>\n" .
|
170 |
+
"</Brand>\n"
|
171 |
+
);
|
172 |
+
}
|
173 |
+
|
174 |
+
protected function writeBrandMultiLocale(Varien_Io_File $ioObject, $brandExternalId, $defaultBrandName, $brandNames)
|
175 |
+
{
|
176 |
+
$ioObject->streamWrite(
|
177 |
+
"<Brand>\n" .
|
178 |
+
" <ExternalId>" . $brandExternalId . "</ExternalId>\n" .
|
179 |
+
" <Name><![CDATA[" . $defaultBrandName . "]]></Name>\n" );
|
180 |
+
// Write out localized <Names>
|
181 |
+
$ioObject->streamWrite(" <Names>\n");
|
182 |
+
foreach ($brandNames as $curLocale => $curBrandName) {
|
183 |
+
$ioObject->streamWrite(' <Name locale="' . $curLocale . '"><![CDATA[' . $curBrandName . "]]></Name>\n");
|
184 |
+
}
|
185 |
+
$ioObject->streamWrite(
|
186 |
+
" </Names>\n" .
|
187 |
+
"</Brand>\n"
|
188 |
+
);
|
189 |
+
}
|
190 |
+
|
191 |
+
}
|
app/code/local/Bazaarvoice/Connector/Model/ProductFeed/Category.php
ADDED
@@ -0,0 +1,301 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @author Bazaarvoice, Inc.
|
4 |
+
*/
|
5 |
+
class Bazaarvoice_Connector_Model_ProductFeed_Category extends Mage_Core_Model_Abstract
|
6 |
+
{
|
7 |
+
private $_categoryIdList = array();
|
8 |
+
|
9 |
+
public function setCategoryIdList(array $list)
|
10 |
+
{
|
11 |
+
$this->_categoryIdList = $list;
|
12 |
+
}
|
13 |
+
|
14 |
+
public function getCategoryIdList()
|
15 |
+
{
|
16 |
+
return $this->_categoryIdList;
|
17 |
+
}
|
18 |
+
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @param Varien_Io_File $ioObject File object for feed file
|
22 |
+
* @param Mage_Core_Model_Website $website
|
23 |
+
*/
|
24 |
+
public function processCategoriesForWebsite(Varien_Io_File $ioObject, Mage_Core_Model_Website $website)
|
25 |
+
{
|
26 |
+
// Lookup category path for root category for default group in this website
|
27 |
+
// NOTE: This means we are only sending the category tree from the default group if there are multiple groups
|
28 |
+
// with different category trees... In that case, admin must configure feed to be generated at group level
|
29 |
+
$rootCategoryId = $website->getDefaultGroup()->getRootCategoryId();
|
30 |
+
/* @var $rootCategory Mage_Catalog_Model_Category */
|
31 |
+
$rootCategory = Mage::getModel('catalog/category')->load($rootCategoryId);
|
32 |
+
$rootCategoryPath = $rootCategory->getData('path');
|
33 |
+
// Get category collection
|
34 |
+
$categoryIds = Mage::getModel('catalog/category')->getCollection();
|
35 |
+
// Filter category collection based on Magento store
|
36 |
+
// Do this by filtering on 'path' attribute, based on root category path found above
|
37 |
+
// Include the root category itself in the feed
|
38 |
+
$categoryIds
|
39 |
+
->addAttributeToFilter('level', array('gt' => 1))
|
40 |
+
->addAttributeToFilter('is_active', 1)
|
41 |
+
->addAttributeToFilter('path', array('like' => $rootCategoryPath . '%'));
|
42 |
+
// Check count of categories
|
43 |
+
if (count($categoryIds) > 0) {
|
44 |
+
$ioObject->streamWrite("<Categories>\n");
|
45 |
+
}
|
46 |
+
/* @var $categoryId Mage_Catalog_Model_Category */
|
47 |
+
foreach ($categoryIds as $categoryId) {
|
48 |
+
// Load version of cat for all store views
|
49 |
+
$categoriesByLocale = array();
|
50 |
+
$categoryDefault = null;
|
51 |
+
/* @var $store Mage_Core_Model_Store */
|
52 |
+
foreach ($website->getStores() as $store) {
|
53 |
+
/* @var $category Mage_Catalog_Model_Category */
|
54 |
+
// Get new category model
|
55 |
+
$category = Mage::getModel('catalog/category');
|
56 |
+
// Set store id before load, to get attribs for this particular store / view
|
57 |
+
$category->setStoreId($store->getId());
|
58 |
+
// Load category object
|
59 |
+
$category->load($categoryId->getId());
|
60 |
+
// Capture localized URL in extra var
|
61 |
+
$category->setData('localized_url', $this->getCategoryUrl($category));
|
62 |
+
// Set default category
|
63 |
+
if ($website->getDefaultGroup()->getDefaultStoreId() == $store->getId()) {
|
64 |
+
$categoryDefault = $category;
|
65 |
+
}
|
66 |
+
// Get store locale
|
67 |
+
$localeCode = Mage::getStoreConfig('bazaarvoice/general/locale', $store->getId());
|
68 |
+
// Check localeCode
|
69 |
+
if (!strlen($localeCode)) {
|
70 |
+
Mage::throwException('Invalid locale code (' . $localeCode . ') configured for store: ' .
|
71 |
+
$store->getCode());
|
72 |
+
}
|
73 |
+
// Add product to array
|
74 |
+
$categoriesByLocale[$localeCode] = $category;
|
75 |
+
}
|
76 |
+
|
77 |
+
$this->writeCategory($ioObject, $categoryDefault, $categoriesByLocale);
|
78 |
+
|
79 |
+
}
|
80 |
+
|
81 |
+
if (count($categoryIds) > 0) {
|
82 |
+
$ioObject->streamWrite("</Categories>\n");
|
83 |
+
}
|
84 |
+
}
|
85 |
+
|
86 |
+
/**
|
87 |
+
* @param Varien_Io_File $ioObject File object for feed file
|
88 |
+
* @param Mage_Core_Model_Store_Group $group
|
89 |
+
*/
|
90 |
+
public function processCategoriesForGroup(Varien_Io_File $ioObject, Mage_Core_Model_Store_Group $group)
|
91 |
+
{
|
92 |
+
// Lookup category path for root category
|
93 |
+
$rootCategoryId = $group->getRootCategoryId();
|
94 |
+
/* @var $rootCategory Mage_Catalog_Model_Category */
|
95 |
+
$rootCategory = Mage::getModel('catalog/category')->load($rootCategoryId);
|
96 |
+
$rootCategoryPath = $rootCategory->getData('path');
|
97 |
+
// Get category collection
|
98 |
+
$categoryIds = Mage::getModel('catalog/category')->getCollection();
|
99 |
+
// Filter category collection based on Magento store
|
100 |
+
// Do this by filtering on 'path' attribute, based on root category path found above
|
101 |
+
// Include the root category itself in the feed
|
102 |
+
$categoryIds
|
103 |
+
->addAttributeToFilter('level', array('gt' => 1))
|
104 |
+
->addAttributeToFilter('is_active', 1)
|
105 |
+
->addAttributeToFilter('path', array('like' => $rootCategoryPath . '%'));
|
106 |
+
// Check count of categories
|
107 |
+
if (count($categoryIds) > 0) {
|
108 |
+
$ioObject->streamWrite("<Categories>\n");
|
109 |
+
}
|
110 |
+
/* @var $categoryId Mage_Catalog_Model_Category */
|
111 |
+
foreach ($categoryIds as $categoryId) {
|
112 |
+
// Load version of cat for all store views
|
113 |
+
$categoriesByLocale = array();
|
114 |
+
$categoryDefault = null;
|
115 |
+
/* @var $store Mage_Core_Model_Store */
|
116 |
+
foreach ($group->getStores() as $store) {
|
117 |
+
/* @var $category Mage_Catalog_Model_Category */
|
118 |
+
// Get new category model
|
119 |
+
$category = Mage::getModel('catalog/category');
|
120 |
+
// Set store id before load, to get attribs for this particular store / view
|
121 |
+
$category->setStoreId($store->getId());
|
122 |
+
// Load category object
|
123 |
+
$category->load($categoryId->getId());
|
124 |
+
// Capture localized URL in extra var
|
125 |
+
$category->setData('localized_url', $this->getCategoryUrl($category));
|
126 |
+
// Set default category
|
127 |
+
if ($group->getDefaultStoreId() == $store->getId()) {
|
128 |
+
$categoryDefault = $category;
|
129 |
+
}
|
130 |
+
// Get store locale
|
131 |
+
$localeCode = Mage::getStoreConfig('bazaarvoice/general/locale', $store->getId());
|
132 |
+
// Check localeCode
|
133 |
+
if (!strlen($localeCode)) {
|
134 |
+
Mage::throwException('Invalid locale code (' . $localeCode . ') configured for store: ' .
|
135 |
+
$store->getCode());
|
136 |
+
}
|
137 |
+
// Add product to array
|
138 |
+
$categoriesByLocale[$localeCode] = $category;
|
139 |
+
}
|
140 |
+
|
141 |
+
$this->writeCategory($ioObject, $categoryDefault, $categoriesByLocale);
|
142 |
+
|
143 |
+
}
|
144 |
+
|
145 |
+
if (count($categoryIds) > 0) {
|
146 |
+
$ioObject->streamWrite("</Categories>\n");
|
147 |
+
}
|
148 |
+
}
|
149 |
+
|
150 |
+
/**
|
151 |
+
* @param Varien_Io_File $ioObject File object for feed file
|
152 |
+
* @param Mage_Core_Model_Store $store
|
153 |
+
*/
|
154 |
+
public function processCategoriesForStore(Varien_Io_File $ioObject, Mage_Core_Model_Store $store)
|
155 |
+
{
|
156 |
+
// Lookup category path for root category
|
157 |
+
$rootCategoryId = $store->getRootCategoryId();
|
158 |
+
/* @var $rootCategory Mage_Catalog_Model_Category */
|
159 |
+
$rootCategory = Mage::getModel('catalog/category')->load($rootCategoryId);
|
160 |
+
$rootCategoryPath = $rootCategory->getData('path');
|
161 |
+
// Get category collection
|
162 |
+
$categoryIds = Mage::getModel('catalog/category')->getCollection();
|
163 |
+
// Filter category collection based on Magento store
|
164 |
+
// Do this by filtering on 'path' attribute, based on root category path found above
|
165 |
+
// Include the root category itself in the feed
|
166 |
+
$categoryIds
|
167 |
+
->addAttributeToFilter('level', array('gt' => 1))
|
168 |
+
->addAttributeToFilter('is_active', 1)
|
169 |
+
->addAttributeToFilter('path', array('like' => $rootCategoryPath . '%'));
|
170 |
+
// Check count of categories
|
171 |
+
if (count($categoryIds) > 0) {
|
172 |
+
$ioObject->streamWrite("<Categories>\n");
|
173 |
+
}
|
174 |
+
/* @var $categoryId Mage_Catalog_Model_Category */
|
175 |
+
foreach ($categoryIds as $categoryId) {
|
176 |
+
// Load version of cat for all store views
|
177 |
+
$categoriesByLocale = array();
|
178 |
+
// Setup parameters for writeCategory, using just this $store
|
179 |
+
/* @var $categoryDefault Mage_Catalog_Model_Category */
|
180 |
+
// Get new category model
|
181 |
+
$categoryDefault = Mage::getModel('catalog/category');
|
182 |
+
// Set store id before load, to get attributes for this particular store / view
|
183 |
+
$categoryDefault->setStoreId($store->getId());
|
184 |
+
// Load category object
|
185 |
+
$categoryDefault->load($categoryId->getId());
|
186 |
+
// Capture localized URL in extra var
|
187 |
+
$categoryDefault->setData('localized_url', $this->getCategoryUrl($categoryDefault));
|
188 |
+
// Get store locale
|
189 |
+
$localeCode = Mage::getStoreConfig('bazaarvoice/general/locale', $store->getId());
|
190 |
+
// Build array of category by locale
|
191 |
+
$categoriesByLocale[$localeCode] = $categoryDefault;
|
192 |
+
// Write category to file
|
193 |
+
$this->writeCategory($ioObject, $categoryDefault, $categoriesByLocale);
|
194 |
+
}
|
195 |
+
|
196 |
+
if (count($categoryIds) > 0) {
|
197 |
+
$ioObject->streamWrite("</Categories>\n");
|
198 |
+
}
|
199 |
+
}
|
200 |
+
|
201 |
+
/**
|
202 |
+
* @param Varien_Io_File $ioObject File object for feed file
|
203 |
+
* @param Mage_Catalog_Model_Category $categoryDefault
|
204 |
+
* @param array $categoriesByLocale
|
205 |
+
*/
|
206 |
+
protected function writeCategory(Varien_Io_File $ioObject, Mage_Catalog_Model_Category $categoryDefault, array $categoriesByLocale)
|
207 |
+
{
|
208 |
+
// Get ref to BV helper
|
209 |
+
/* @var $bvHelper Bazaarvoice_Connector_Helper_Data */
|
210 |
+
$bvHelper = Mage::helper('bazaarvoice');
|
211 |
+
|
212 |
+
// Get external id
|
213 |
+
$categoryExternalId = $bvHelper->getCategoryId($categoryDefault, $categoryDefault->getStoreId());
|
214 |
+
|
215 |
+
$categoryName = htmlspecialchars($categoryDefault->getName(), ENT_QUOTES, 'UTF-8');
|
216 |
+
$categoryPageUrl = htmlspecialchars($categoryDefault->getData('localized_url'), ENT_QUOTES, 'UTF-8');
|
217 |
+
|
218 |
+
$parentExtId = '';
|
219 |
+
/* @var $parentCategory Mage_Catalog_Model_Category */
|
220 |
+
$parentCategory = Mage::getModel('catalog/category')->load($categoryDefault->getParentId());
|
221 |
+
// If parent category is the root category, then ignore it
|
222 |
+
if (!is_null($parentCategory) && $parentCategory->getLevel() != 1) {
|
223 |
+
$parentExtId = ' <ParentExternalId>' .
|
224 |
+
$bvHelper->getCategoryId($parentCategory, $categoryDefault->getStoreId()) . "</ParentExternalId>\n";
|
225 |
+
}
|
226 |
+
|
227 |
+
array_push($this->_categoryIdList, $categoryExternalId);
|
228 |
+
|
229 |
+
$ioObject->streamWrite("<Category>\n" .
|
230 |
+
" <ExternalId>" . $categoryExternalId . "</ExternalId>\n" .
|
231 |
+
$parentExtId .
|
232 |
+
" <Name><![CDATA[" . $categoryName . "]]></Name>\n" .
|
233 |
+
" <CategoryPageUrl><![CDATA[" . $categoryPageUrl . "]]></CategoryPageUrl>\n");
|
234 |
+
|
235 |
+
// Write out localized <Names>
|
236 |
+
$ioObject->streamWrite(" <Names>\n");
|
237 |
+
/* @var $curCategory Mage_Catalog_Model_Category */
|
238 |
+
foreach ($categoriesByLocale as $curLocale => $curCategory) {
|
239 |
+
$ioObject->streamWrite(' <Name locale="' . $curLocale . '"><![CDATA[' .
|
240 |
+
htmlspecialchars($curCategory->getName(), ENT_QUOTES, 'UTF-8') . "]]></Name>\n");
|
241 |
+
}
|
242 |
+
$ioObject->streamWrite(" </Names>\n");
|
243 |
+
// Write out localized <CategoryPageUrls>
|
244 |
+
$ioObject->streamWrite(" <CategoryPageUrls>\n");
|
245 |
+
/* @var $curCategory Mage_Catalog_Model_Category */
|
246 |
+
foreach ($categoriesByLocale as $curLocale => $curCategory) {
|
247 |
+
$ioObject->streamWrite(' <CategoryPageUrl locale="' . $curLocale . '">' . "<![CDATA[" .
|
248 |
+
htmlspecialchars($curCategory->getData('localized_url'), ENT_QUOTES, 'UTF-8') . "]]>" . "</CategoryPageUrl>\n");
|
249 |
+
}
|
250 |
+
$ioObject->streamWrite(" </CategoryPageUrls>\n");
|
251 |
+
|
252 |
+
$ioObject->streamWrite("</Category>\n");
|
253 |
+
|
254 |
+
}
|
255 |
+
|
256 |
+
/**
|
257 |
+
* Method to retrieve Magento category URL, modeled after Mage_Catalog_Model_Category::getUrl in EE 1.12
|
258 |
+
*
|
259 |
+
* @param Mage_Catalog_Model_Category $category
|
260 |
+
* @return string
|
261 |
+
*/
|
262 |
+
protected function getCategoryUrl(Mage_Catalog_Model_Category $category)
|
263 |
+
{
|
264 |
+
/** @var Mage_Core_Model_Url $urlInstance */
|
265 |
+
$urlInstance = Mage::getModel('core/url');
|
266 |
+
$urlInstance->setStore($category->getStoreId());
|
267 |
+
$url = $category->_getData('url');
|
268 |
+
if (is_null($url)) {
|
269 |
+
Varien_Profiler::start('REWRITE: '.__METHOD__);
|
270 |
+
|
271 |
+
if ($category->hasData('request_path') && $category->getRequestPath() != '') {
|
272 |
+
$category->setData('url', $urlInstance->getDirectUrl($category->getRequestPath()));
|
273 |
+
Varien_Profiler::stop('REWRITE: '.__METHOD__);
|
274 |
+
return $category->getData('url');
|
275 |
+
}
|
276 |
+
|
277 |
+
Varien_Profiler::stop('REWRITE: '.__METHOD__);
|
278 |
+
|
279 |
+
$rewrite = $category->getUrlRewrite();
|
280 |
+
if ($category->getStoreId()) {
|
281 |
+
$rewrite->setStoreId($category->getStoreId());
|
282 |
+
}
|
283 |
+
$idPath = 'category/' . $category->getId();
|
284 |
+
$rewrite->loadByIdPath($idPath);
|
285 |
+
|
286 |
+
if ($rewrite->getId()) {
|
287 |
+
Mage::log('request path: ' . $rewrite->getRequestPath());
|
288 |
+
$category->setData('url', $urlInstance->getDirectUrl($rewrite->getRequestPath()));
|
289 |
+
Varien_Profiler::stop('REWRITE: '.__METHOD__);
|
290 |
+
return $category->getData('url');
|
291 |
+
}
|
292 |
+
|
293 |
+
Varien_Profiler::stop('REWRITE: '.__METHOD__);
|
294 |
+
|
295 |
+
$category->setData('url', $category->getCategoryIdUrl());
|
296 |
+
return $category->getData('url');
|
297 |
+
}
|
298 |
+
return $url;
|
299 |
+
}
|
300 |
+
|
301 |
+
}
|
app/code/local/Bazaarvoice/Connector/Model/ProductFeed/Product.php
ADDED
@@ -0,0 +1,333 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @author Bazaarvoice, Inc.
|
4 |
+
*/
|
5 |
+
class Bazaarvoice_Connector_Model_ProductFeed_Product extends Mage_Core_Model_Abstract
|
6 |
+
{
|
7 |
+
private $_categoryIdList = array();
|
8 |
+
|
9 |
+
public function setCategoryIdList(array $list)
|
10 |
+
{
|
11 |
+
$this->_categoryIdList = $list;
|
12 |
+
}
|
13 |
+
|
14 |
+
public function getCategoryIdList()
|
15 |
+
{
|
16 |
+
return $this->_categoryIdList;
|
17 |
+
}
|
18 |
+
|
19 |
+
/**
|
20 |
+
*
|
21 |
+
* @param Varien_Io_File $ioObject File object for feed file
|
22 |
+
* @param Mage_Core_Model_Website $website
|
23 |
+
*/
|
24 |
+
public function processProductsForWebsite(Varien_Io_File $ioObject, Mage_Core_Model_Website $website)
|
25 |
+
{
|
26 |
+
// *FROM MEMORY* this should get all the products
|
27 |
+
$productIds = Mage::getModel('catalog/product')->getCollection();
|
28 |
+
// Filter collection for the specific website
|
29 |
+
$productIds->addWebsiteFilter($website->getId());
|
30 |
+
// Filter collection for product status
|
31 |
+
$productIds->addAttributeToFilter('status', Mage_Catalog_Model_Product_Status::STATUS_ENABLED);
|
32 |
+
// Filter collection for product visibility
|
33 |
+
$productIds->addAttributeToFilter('visibility', array('neq' => Mage_Catalog_Model_Product_Visibility::VISIBILITY_NOT_VISIBLE));
|
34 |
+
|
35 |
+
// Output tag only if more than 1 product
|
36 |
+
if (count($productIds) > 0) {
|
37 |
+
$ioObject->streamWrite("<Products>\n");
|
38 |
+
}
|
39 |
+
/* @var $productId Mage_Catalog_Model_Product */
|
40 |
+
foreach ($productIds as $productId) {
|
41 |
+
// Load version of product for all store views
|
42 |
+
$productsByLocale = array();
|
43 |
+
/* @var $productDefault Mage_Catalog_Model_Product */
|
44 |
+
$productDefault = null;
|
45 |
+
/* @var $store Mage_Core_Model_Store */
|
46 |
+
foreach ($website->getStores() as $store) {
|
47 |
+
/* @var $product Mage_Catalog_Model_Product */
|
48 |
+
// Get new product model
|
49 |
+
$product = Mage::getModel('catalog/product');
|
50 |
+
// Set store id before load, to get attribs for this particular store / view
|
51 |
+
$product->setStoreId($store->getId());
|
52 |
+
// Load product object
|
53 |
+
$product->load($productId->getId());
|
54 |
+
// Set localized product and image url
|
55 |
+
$product->setData('localized_image_url', $this->getProductImageUrl($product));
|
56 |
+
// Set bazaarvoice specific attributes
|
57 |
+
// Brand
|
58 |
+
$brandAttributeCode = Mage::getStoreConfig('bazaarvoice/bv_config/product_feed_brand_attribute_code', $store->getId());
|
59 |
+
if (strlen(trim($brandAttributeCode))) {
|
60 |
+
$brand = $product->getData($brandAttributeCode);
|
61 |
+
$product->setData('brand', $brand);
|
62 |
+
}
|
63 |
+
// Set default product
|
64 |
+
if ($website->getDefaultGroup()->getDefaultStoreId() == $store->getId()) {
|
65 |
+
$productDefault = $product;
|
66 |
+
}
|
67 |
+
// Get store locale
|
68 |
+
$localeCode = Mage::getStoreConfig('bazaarvoice/general/locale', $store->getId());
|
69 |
+
// Check localeCode
|
70 |
+
if (!strlen($localeCode)) {
|
71 |
+
Mage::throwException('Invalid locale code (' . $localeCode . ') configured for store: ' .
|
72 |
+
$store->getCode());
|
73 |
+
}
|
74 |
+
// Add product to array
|
75 |
+
$productsByLocale[$localeCode] = $product;
|
76 |
+
}
|
77 |
+
|
78 |
+
// Write out individual product
|
79 |
+
$this->writeProduct($ioObject, $productDefault, $productsByLocale);
|
80 |
+
|
81 |
+
}
|
82 |
+
if (count($productIds) > 0) {
|
83 |
+
$ioObject->streamWrite("</Products>\n");
|
84 |
+
}
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
*
|
89 |
+
* @param Varien_Io_File $ioObject File object for feed file
|
90 |
+
* @param Mage_Core_Model_Store_Group $group Store Group
|
91 |
+
*/
|
92 |
+
public function processProductsForGroup(Varien_Io_File $ioObject, Mage_Core_Model_Store_Group $group)
|
93 |
+
{
|
94 |
+
// *FROM MEMORY* this should get all the products
|
95 |
+
$productIds = Mage::getModel('catalog/product')->getCollection();
|
96 |
+
// Filter collection for the specific website
|
97 |
+
$productIds->addWebsiteFilter($group->getWebsiteId());
|
98 |
+
// Filter collection for product status
|
99 |
+
$productIds->addAttributeToFilter('status', Mage_Catalog_Model_Product_Status::STATUS_ENABLED);
|
100 |
+
// Filter collection for product visibility
|
101 |
+
$productIds->addAttributeToFilter('visibility',
|
102 |
+
array('neq' => Mage_Catalog_Model_Product_Visibility::VISIBILITY_NOT_VISIBLE));
|
103 |
+
|
104 |
+
// Output tag only if more than 1 product
|
105 |
+
if (count($productIds) > 0) {
|
106 |
+
$ioObject->streamWrite("<Products>\n");
|
107 |
+
}
|
108 |
+
/* @var $productId Mage_Catalog_Model_Product */
|
109 |
+
foreach ($productIds as $productId) {
|
110 |
+
// Load version of product for all store views
|
111 |
+
$productsByLocale = array();
|
112 |
+
/* @var $productDefault Mage_Catalog_Model_Product */
|
113 |
+
$productDefault = null;
|
114 |
+
/* @var $store Mage_Core_Model_Store */
|
115 |
+
foreach ($group->getStores() as $store) {
|
116 |
+
/* @var $product Mage_Catalog_Model_Product */
|
117 |
+
// Get new product model
|
118 |
+
$product = Mage::getModel('catalog/product');
|
119 |
+
// Set store id before load, to get attributes for this particular store / view
|
120 |
+
$product->setStoreId($store->getId());
|
121 |
+
// Load product object
|
122 |
+
$product->load($productId->getId());
|
123 |
+
// Set localized product and image url
|
124 |
+
$product->setData('localized_image_url', $this->getProductImageUrl($product));
|
125 |
+
// Set bazaarvoice specific attributes
|
126 |
+
$brandAttributeCode = Mage::getStoreConfig('bazaarvoice/bv_config/product_feed_brand_attribute_code', $store->getId());
|
127 |
+
if (strlen(trim($brandAttributeCode))) {
|
128 |
+
$brand = $product->getData($brandAttributeCode);
|
129 |
+
$product->setData('brand', $brand);
|
130 |
+
}
|
131 |
+
// Set default product
|
132 |
+
if ($group->getDefaultStoreId() == $store->getId()) {
|
133 |
+
$productDefault = $product;
|
134 |
+
}
|
135 |
+
// Get store locale
|
136 |
+
$localeCode = Mage::getStoreConfig('bazaarvoice/general/locale', $store->getId());
|
137 |
+
// Check localeCode
|
138 |
+
if (!strlen($localeCode)) {
|
139 |
+
Mage::throwException('Invalid locale code (' . $localeCode . ') configured for store: ' .
|
140 |
+
$store->getCode());
|
141 |
+
}
|
142 |
+
// Add product to array
|
143 |
+
$productsByLocale[$localeCode] = $product;
|
144 |
+
}
|
145 |
+
|
146 |
+
// Write out individual product
|
147 |
+
$this->writeProduct($ioObject, $productDefault, $productsByLocale);
|
148 |
+
|
149 |
+
}
|
150 |
+
if (count($productIds) > 0) {
|
151 |
+
$ioObject->streamWrite("</Products>\n");
|
152 |
+
}
|
153 |
+
}
|
154 |
+
|
155 |
+
/**
|
156 |
+
* @param Varien_Io_File $ioObject File object for feed file
|
157 |
+
* @param Mage_Core_Model_Store $store
|
158 |
+
*/
|
159 |
+
public function processProductsForStore(Varien_Io_File $ioObject, Mage_Core_Model_Store $store)
|
160 |
+
{
|
161 |
+
// *FROM MEMORY* this should get all the products
|
162 |
+
$productIds = Mage::getModel('catalog/product')->getCollection();
|
163 |
+
// Filter collection for the specific website
|
164 |
+
$productIds->addWebsiteFilter($store->getWebsiteId());
|
165 |
+
// Filter collection for product status
|
166 |
+
$productIds->addAttributeToFilter('status', Mage_Catalog_Model_Product_Status::STATUS_ENABLED);
|
167 |
+
// Filter collection for product visibility
|
168 |
+
$productIds->addAttributeToFilter('visibility',
|
169 |
+
array('neq' => Mage_Catalog_Model_Product_Visibility::VISIBILITY_NOT_VISIBLE));
|
170 |
+
|
171 |
+
// Output tag only if more than 1 product
|
172 |
+
if (count($productIds) > 0) {
|
173 |
+
$ioObject->streamWrite("<Products>\n");
|
174 |
+
}
|
175 |
+
/* @var $productId Mage_Catalog_Model_Product */
|
176 |
+
foreach ($productIds as $productId) {
|
177 |
+
// Load version of product for all store views
|
178 |
+
$productsByLocale = array();
|
179 |
+
/* @var $productDefault Mage_Catalog_Model_Product */
|
180 |
+
$productDefault = Mage::getModel('catalog/product');
|
181 |
+
// Set store id before load, to get attributes for this particular store / view
|
182 |
+
$productDefault->setStoreId($store->getId());
|
183 |
+
// Load product object
|
184 |
+
$productDefault->load($productId->getId());
|
185 |
+
// Set localized product and image url
|
186 |
+
$productDefault->setData('localized_image_url', $this->getProductImageUrl($productDefault));
|
187 |
+
// Set bazaarvoice specific attributes
|
188 |
+
$brandAttributeCode = Mage::getStoreConfig('bazaarvoice/bv_config/product_feed_brand_attribute_code', $store->getId());
|
189 |
+
if (strlen(trim($brandAttributeCode))) {
|
190 |
+
$brand = $productDefault->getData($brandAttributeCode);
|
191 |
+
$productDefault->setData('brand', $brand);
|
192 |
+
}
|
193 |
+
// Get store locale
|
194 |
+
$localeCode = Mage::getStoreConfig('bazaarvoice/general/locale', $store->getId());
|
195 |
+
// Check localeCode
|
196 |
+
if (!strlen($localeCode)) {
|
197 |
+
Mage::throwException('Invalid locale code (' . $localeCode . ') configured for store: ' .
|
198 |
+
$store->getCode());
|
199 |
+
}
|
200 |
+
// Add product to array
|
201 |
+
$productsByLocale[$localeCode] = $productDefault;
|
202 |
+
// Write out individual product
|
203 |
+
$this->writeProduct($ioObject, $productDefault, $productsByLocale);
|
204 |
+
}
|
205 |
+
if (count($productIds) > 0) {
|
206 |
+
$ioObject->streamWrite("</Products>\n");
|
207 |
+
}
|
208 |
+
}
|
209 |
+
|
210 |
+
/**
|
211 |
+
* @param Varien_Io_File $ioObject File object for feed file
|
212 |
+
* @param Mage_Catalog_Model_Product $productDefault
|
213 |
+
* @param array $productsByLocale
|
214 |
+
*/
|
215 |
+
protected function writeProduct(Varien_Io_File $ioObject, Mage_Catalog_Model_Product $productDefault,
|
216 |
+
array $productsByLocale)
|
217 |
+
{
|
218 |
+
// Get ref to BV helper
|
219 |
+
/* @var $bvHelper Bazaarvoice_Connector_Helper_Data */
|
220 |
+
$bvHelper = Mage::helper('bazaarvoice');
|
221 |
+
|
222 |
+
// Generate product external ID from SKU, this is the same for all groups / stores / views
|
223 |
+
$productExternalId = $bvHelper->getProductId($productDefault);
|
224 |
+
|
225 |
+
$ioObject->streamWrite("<Product>\n" .
|
226 |
+
' <ExternalId>' . $productExternalId . "</ExternalId>\n" .
|
227 |
+
' <Name><![CDATA[' . htmlspecialchars($productDefault->getName(), ENT_QUOTES, 'UTF-8') . "]]></Name>\n" .
|
228 |
+
' <Description><![CDATA[' . htmlspecialchars($productDefault->getData('short_description'), ENT_QUOTES, 'UTF-8') .
|
229 |
+
"]]></Description>\n");
|
230 |
+
|
231 |
+
$brandId = $productDefault->getData('brand');
|
232 |
+
if ($productDefault->hasData('brand') && !is_null($brandId) && !empty($brandId)) {
|
233 |
+
$ioObject->streamWrite(' <Brand><ExternalId>' . $brandId . "</ExternalId></Brand>\n");
|
234 |
+
}
|
235 |
+
|
236 |
+
/* Make sure that CategoryExternalId is one written to Category section */
|
237 |
+
$parentCategories = $productDefault->getCategoryIds();
|
238 |
+
if (!is_null($parentCategories) && count($parentCategories) > 0) {
|
239 |
+
foreach ($parentCategories as $parentCategoryId) {
|
240 |
+
$parentCategory = Mage::getModel('catalog/category')->load($parentCategoryId);
|
241 |
+
if ($parentCategory != null) {
|
242 |
+
$categoryExternalId = $bvHelper->getCategoryId($parentCategory, $productDefault->getStoreId());
|
243 |
+
if (in_array($categoryExternalId, $this->_categoryIdList)) {
|
244 |
+
$ioObject->streamWrite(' <CategoryExternalId>' . $categoryExternalId .
|
245 |
+
"</CategoryExternalId>\n");
|
246 |
+
break;
|
247 |
+
}
|
248 |
+
}
|
249 |
+
}
|
250 |
+
}
|
251 |
+
|
252 |
+
$ioObject->streamWrite(' <ProductPageUrl>' . "<![CDATA[" . $this->getProductUrl($productDefault) . "]]>" . "</ProductPageUrl>\n");
|
253 |
+
$imageUrl = $productDefault->getData('localized_image_url');
|
254 |
+
if (strlen($imageUrl)) {
|
255 |
+
$ioObject->streamWrite(' <ImageUrl>' . "<![CDATA[" . $imageUrl . "]]>" . "</ImageUrl>\n");
|
256 |
+
}
|
257 |
+
|
258 |
+
// Write out localized <Names>
|
259 |
+
$ioObject->streamWrite(" <Names>\n");
|
260 |
+
foreach ($productsByLocale as $curLocale => $curProduct) {
|
261 |
+
$ioObject->streamWrite(' <Name locale="' . $curLocale . '"><![CDATA[' .
|
262 |
+
htmlspecialchars($productDefault->getData('name'), ENT_QUOTES, 'UTF-8') . "]]></Name>\n");
|
263 |
+
}
|
264 |
+
$ioObject->streamWrite(" </Names>\n");
|
265 |
+
// Write out localized <Descriptions>
|
266 |
+
$ioObject->streamWrite(" <Descriptions>\n");
|
267 |
+
foreach ($productsByLocale as $curLocale => $curProduct) {
|
268 |
+
$ioObject->streamWrite(' <Description locale="' . $curLocale . '"><![CDATA[' .
|
269 |
+
htmlspecialchars($productDefault->getData('short_description'), ENT_QUOTES, 'UTF-8') . "]]></Description>\n");
|
270 |
+
}
|
271 |
+
$ioObject->streamWrite(" </Descriptions>\n");
|
272 |
+
// Write out localized <ProductPageUrls>
|
273 |
+
$ioObject->streamWrite(" <ProductPageUrls>\n");
|
274 |
+
foreach ($productsByLocale as $curLocale => $curProduct) {
|
275 |
+
$ioObject->streamWrite(' <ProductPageUrl locale="' . $curLocale . '">' . "<![CDATA[" .
|
276 |
+
$this->getProductUrl($curProduct) . "]]>" . "</ProductPageUrl>\n");
|
277 |
+
}
|
278 |
+
$ioObject->streamWrite(" </ProductPageUrls>\n");
|
279 |
+
// Write out localized <ImageUrls>
|
280 |
+
$ioObject->streamWrite(" <ImageUrls>\n");
|
281 |
+
foreach ($productsByLocale as $curLocale => $curProduct) {
|
282 |
+
$imageUrl = $curProduct->getData('localized_image_url');
|
283 |
+
if (strlen($imageUrl)) {
|
284 |
+
$ioObject->streamWrite(' <ImageUrl locale="' . $curLocale . '">' . "<![CDATA[" . $imageUrl .
|
285 |
+
"]]>" . "</ImageUrl>\n");
|
286 |
+
}
|
287 |
+
}
|
288 |
+
$ioObject->streamWrite(" </ImageUrls>\n");
|
289 |
+
|
290 |
+
// Close this product
|
291 |
+
$ioObject->streamWrite("</Product>\n");
|
292 |
+
}
|
293 |
+
|
294 |
+
protected function getProductImageUrl(Mage_Catalog_Model_Product $product)
|
295 |
+
{
|
296 |
+
try {
|
297 |
+
// Init return var
|
298 |
+
$imageUrl = null;
|
299 |
+
// Get store id from product
|
300 |
+
$storeId = $product->getStoreId();
|
301 |
+
// Get image url from helper (this is for the default store
|
302 |
+
$defaultStoreImageUrl = Mage::helper('catalog/image')->init($product, 'image');
|
303 |
+
// Get media base url for correct store
|
304 |
+
$mediaBaseUrl = Mage::app()->getStore($storeId)->getBaseUrl('media');
|
305 |
+
// Get default media base url
|
306 |
+
$defaultMediaBaseUrl = Mage::getBaseUrl('media');
|
307 |
+
// Replace media base url component
|
308 |
+
$imageUrl = str_replace($defaultMediaBaseUrl, $mediaBaseUrl, $defaultStoreImageUrl);
|
309 |
+
|
310 |
+
// Return resulting url
|
311 |
+
return $imageUrl;
|
312 |
+
}
|
313 |
+
catch (Exception $e) {
|
314 |
+
Mage::log('Failed to get image URL for product sku: ' . $product->getSku());
|
315 |
+
Mage::log('Continuing generating feed.');
|
316 |
+
|
317 |
+
return '';
|
318 |
+
}
|
319 |
+
}
|
320 |
+
|
321 |
+
protected function getProductUrl(Mage_Catalog_Model_Product $product)
|
322 |
+
{
|
323 |
+
$productUrl = $product->getProductUrl(false);
|
324 |
+
// Trim any url params
|
325 |
+
$questionMarkPos = strpos($productUrl, '?');
|
326 |
+
if($questionMarkPos !== FALSE) {
|
327 |
+
$productUrl = substr($productUrl, 0, $questionMarkPos);
|
328 |
+
}
|
329 |
+
|
330 |
+
return $productUrl;
|
331 |
+
}
|
332 |
+
|
333 |
+
}
|
app/code/local/Bazaarvoice/Connector/Model/RetrieveInlineRatingsFeed.php
ADDED
@@ -0,0 +1,219 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @author Bazaarvoice, Inc.
|
4 |
+
*/
|
5 |
+
class Bazaarvoice_Connector_Model_RetrieveInlineRatingsFeed extends Mage_Core_Model_Abstract
|
6 |
+
{
|
7 |
+
|
8 |
+
// Set this value to true to enable the the inline ratings feed on a scheduled basis
|
9 |
+
const INLINE_RATINGS_FEED_ENABLED = false;
|
10 |
+
// Hard code feed file name in const for easy customization
|
11 |
+
const FEED_FILENAME = 'bv_ratings.xml.gz';
|
12 |
+
|
13 |
+
protected function _construct()
|
14 |
+
{
|
15 |
+
}
|
16 |
+
|
17 |
+
public function retrieveInlineRatingsFeed()
|
18 |
+
{
|
19 |
+
// Log
|
20 |
+
Mage::log('Start Bazaarvoice Inline Ratings feed import');
|
21 |
+
// Iterate through all stores / groups in this instance
|
22 |
+
// (Not the 'admin' store view, which represents admin panel)
|
23 |
+
$groups = Mage::app()->getGroups(false);
|
24 |
+
/** @var $group Mage_Core_Model_Store_Group */
|
25 |
+
foreach ($groups as $group) {
|
26 |
+
try {
|
27 |
+
if (self::INLINE_RATINGS_FEED_ENABLED && Mage::getStoreConfig('bazaarvoice/general/enable_bv', $group->getDefaultStoreId()) === '1') {
|
28 |
+
if(count($group->getStores()) > 0) {
|
29 |
+
Mage::log(' BV - Importing Inline Ratings feed for store group: ' . $group->getName(), Zend_Log::INFO);
|
30 |
+
$this->retrieveInlineRatingsFeedForStoreGroup($group);
|
31 |
+
}
|
32 |
+
else {
|
33 |
+
Mage::throwException('No stores for store group: ' . $group->getName());
|
34 |
+
}
|
35 |
+
}
|
36 |
+
else {
|
37 |
+
Mage::log(' BV - Inline Ratings feed disabled for store group: ' . $group->getName(), Zend_Log::INFO);
|
38 |
+
}
|
39 |
+
} catch (Exception $e) {
|
40 |
+
Mage::log(' BV - Failed to import Inline Ratings feed for store group: ' . $group->getName(), Zend_Log::ERR);
|
41 |
+
Mage::log(' BV - Error message: ' . $e->getMessage(), Zend_Log::ERR);
|
42 |
+
Mage::logException($e);
|
43 |
+
// Continue processing other store groups
|
44 |
+
}
|
45 |
+
}
|
46 |
+
// Log
|
47 |
+
Mage::log('End Bazaarvoice Inline Ratings feed import');
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
*
|
52 |
+
* @param Mage_Core_Model_Store_Group $group Store Group
|
53 |
+
*
|
54 |
+
*/
|
55 |
+
public function retrieveInlineRatingsFeedForStoreGroup($group)
|
56 |
+
{
|
57 |
+
if (self::INLINE_RATINGS_FEED_ENABLED && Mage::getStoreConfig('bazaarvoice/general/enable_bv', $group->getDefaultStoreId()) === '1') {
|
58 |
+
$localFilePath = Mage::getBaseDir('var') . DS . 'import' . DS . 'bvfeeds';
|
59 |
+
$localFileName = 'inline-ratings-' . $group->getGroupId() . '-' . date('U') . '.xml';
|
60 |
+
$gzLocalFilename = $localFileName . '.gz';
|
61 |
+
// Hard code feed file path
|
62 |
+
$remoteFile = '/feeds/' . self::FEED_FILENAME;
|
63 |
+
|
64 |
+
if (!Mage::helper('bazaarvoice')->downloadFile($localFilePath, $gzLocalFilename, $remoteFile)) {
|
65 |
+
// Unable to download the file. Check magento log for messages.
|
66 |
+
Mage::throwException(' BV - unable to process feed. Check the Magento log for further information.');
|
67 |
+
}
|
68 |
+
|
69 |
+
// Unpack the file
|
70 |
+
if (file_exists($localFilePath . DS . $localFileName)) {
|
71 |
+
unlink($localFilePath . DS . $localFileName);
|
72 |
+
}
|
73 |
+
$gzInterface = new Mage_Archive_Gz();
|
74 |
+
$gzInterface->unpack($localFilePath . DS . $gzLocalFilename, $localFilePath . DS . $localFileName);
|
75 |
+
|
76 |
+
// Create custom product attributes
|
77 |
+
$this->createProductAttributesIfNecessary();
|
78 |
+
|
79 |
+
// Parse the XML
|
80 |
+
$this->parseFeed($localFilePath . DS . $localFileName);
|
81 |
+
|
82 |
+
// Cleanup
|
83 |
+
if (file_exists($localFilePath . DS . $localFileName)) {
|
84 |
+
unlink($localFilePath . DS . $localFileName);
|
85 |
+
}
|
86 |
+
if (file_exists($localFilePath . DS . $gzLocalFilename)) {
|
87 |
+
unlink($localFilePath . DS . $gzLocalFilename);
|
88 |
+
}
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
|
93 |
+
private function parseFeed($fileName)
|
94 |
+
{
|
95 |
+
// Use XMLReader to parse the feed. Should be available in all PHP5 environments, which is a pre-req of Magento
|
96 |
+
// http://devzone.zend.com/article/2387
|
97 |
+
|
98 |
+
$reader = new XMLReader();
|
99 |
+
$reader->open($fileName);
|
100 |
+
while ($reader->read()) {
|
101 |
+
if (($reader->nodeType == XMLReader::ELEMENT)
|
102 |
+
&& ($reader->localName == 'Product')) {
|
103 |
+
|
104 |
+
$this->processProduct($reader);
|
105 |
+
|
106 |
+
}
|
107 |
+
}
|
108 |
+
|
109 |
+
}
|
110 |
+
|
111 |
+
private function processProduct($xmlReader)
|
112 |
+
{
|
113 |
+
$endOfProduct = false;
|
114 |
+
|
115 |
+
$bvProductExternalId = $xmlReader->getAttribute('id');
|
116 |
+
$productAverageRating = 0;
|
117 |
+
$productReviewCount = 0;
|
118 |
+
$productRatingRange = 5;
|
119 |
+
|
120 |
+
|
121 |
+
while (!$endOfProduct && $xmlReader->read()) {
|
122 |
+
if ($xmlReader->nodeType == XMLReader::ELEMENT) {
|
123 |
+
|
124 |
+
if ($xmlReader->localName == 'AverageOverallRating') {
|
125 |
+
|
126 |
+
$productAverageRating = $xmlReader->readString();
|
127 |
+
|
128 |
+
} elseif ($xmlReader->localName == 'OverallRatingRange') {
|
129 |
+
|
130 |
+
$productRatingRange = $xmlReader->readString();
|
131 |
+
|
132 |
+
} elseif ($xmlReader->localName == 'TotalReviewCount') {
|
133 |
+
|
134 |
+
$productReviewCount = $xmlReader->readString();
|
135 |
+
|
136 |
+
}
|
137 |
+
|
138 |
+
} elseif (($xmlReader->nodeType == XMLReader::END_ELEMENT)
|
139 |
+
&& ($xmlReader->localName == 'Product')) {
|
140 |
+
$endOfProduct = true;
|
141 |
+
}
|
142 |
+
}
|
143 |
+
|
144 |
+
// Persist data for this product
|
145 |
+
$product = Mage::helper('bazaarvoice')->getProductFromProductExternalId($bvProductExternalId);
|
146 |
+
if (!is_null($product)) {
|
147 |
+
$product->setBvAverageRating($productAverageRating);
|
148 |
+
$product->setBvReviewCount($productReviewCount);
|
149 |
+
$product->setBvRatingRange($productRatingRange);
|
150 |
+
$product->getResource()->saveAttribute($product, 'bv_average_rating');
|
151 |
+
$product->getResource()->saveAttribute($product, 'bv_review_count');
|
152 |
+
$product->getResource()->saveAttribute($product, 'bv_rating_range');
|
153 |
+
|
154 |
+
Mage::log(' BV - InlineRating for product ' . $bvProductExternalId . ' = {' . $productAverageRating . ', ' . $productReviewCount . ', ' . $productRatingRange . '}');
|
155 |
+
} else {
|
156 |
+
Mage::log(" BV - Could not find product for ExternalID '" . $bvProductExternalId . "'");
|
157 |
+
}
|
158 |
+
}
|
159 |
+
|
160 |
+
private function createProductAttributesIfNecessary()
|
161 |
+
{
|
162 |
+
$attributeModel = Mage::getModel('catalog/resource_eav_attribute');
|
163 |
+
$entityTypeId = Mage::getModel('eav/entity')->setType('catalog_product')->getTypeId();
|
164 |
+
|
165 |
+
$customAttributes = array('bv_average_rating', 'bv_review_count', 'bv_rating_range');
|
166 |
+
|
167 |
+
foreach ($customAttributes as $customAttribute) {
|
168 |
+
$attribute = $attributeModel->loadByCode($entityTypeId, $customAttribute);
|
169 |
+
if (!$attribute->getId()) {
|
170 |
+
$this->createProductAttribute($customAttribute);
|
171 |
+
}
|
172 |
+
}
|
173 |
+
}
|
174 |
+
|
175 |
+
private function createProductAttribute($attribCode)
|
176 |
+
{
|
177 |
+
|
178 |
+
$model = Mage::getModel('catalog/resource_eav_attribute');
|
179 |
+
|
180 |
+
$data = array(
|
181 |
+
'attribute_code' => $attribCode,
|
182 |
+
'is_global' => '1',
|
183 |
+
'frontend_input' => 'text', // equivalent of a text field
|
184 |
+
'default_value_text' => '',
|
185 |
+
'default_value_yesno' => '0',
|
186 |
+
'default_value_date' => '',
|
187 |
+
'default_value_textarea' => '',
|
188 |
+
'is_unique' => '0',
|
189 |
+
'is_required' => '0',
|
190 |
+
// 'apply_to' => array(), // Apply to everything
|
191 |
+
'is_configurable' => '0',
|
192 |
+
'is_filterable' => '0',
|
193 |
+
'is_filterable_in_search' => '0',
|
194 |
+
'is_searchable' => '1',
|
195 |
+
'is_visible_in_advanced_search' => '1',
|
196 |
+
'is_comparable' => '0',
|
197 |
+
'is_used_for_price_rules' => '0',
|
198 |
+
'is_wysiwyg_enabled' => '0',
|
199 |
+
'is_html_allowed_on_front' => '1',
|
200 |
+
'is_visible_on_front' => '1',
|
201 |
+
'used_in_product_listing' => '1',
|
202 |
+
'used_for_sort_by' => '0',
|
203 |
+
'frontend_label' => array($attribCode)
|
204 |
+
);
|
205 |
+
|
206 |
+
$data['backend_type'] = 'decimal'; // $model->getBackendTypeByInput($data['frontend_input']);
|
207 |
+
|
208 |
+
$model->addData($data);
|
209 |
+
$model->setEntityTypeId(Mage::getModel('eav/entity')->setType('catalog_product')->getTypeId());
|
210 |
+
$model->setIsUserDefined(1);
|
211 |
+
try {
|
212 |
+
$model->save();
|
213 |
+
} catch (Exception $e) {
|
214 |
+
|
215 |
+
}
|
216 |
+
}
|
217 |
+
|
218 |
+
}
|
219 |
+
|
app/code/local/Bazaarvoice/Connector/Model/RetrieveSmartSEOPackage.php
ADDED
@@ -0,0 +1,143 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @author Bazaarvoice, Inc.
|
4 |
+
*/
|
5 |
+
class Bazaarvoice_Connector_Model_RetrieveSmartSEOPackage extends Mage_Core_Model_Abstract
|
6 |
+
{
|
7 |
+
|
8 |
+
protected function _construct()
|
9 |
+
{
|
10 |
+
}
|
11 |
+
|
12 |
+
public function retrieveSmartSEOPackage()
|
13 |
+
{
|
14 |
+
// Disable smart SEO feed for now
|
15 |
+
Mage::log('Smart SEO feed import is not enabled!');
|
16 |
+
return;
|
17 |
+
// Log
|
18 |
+
Mage::log('Start Bazaarvoice Smart SEO feed import');
|
19 |
+
// Iterate through all stores / groups in this instance
|
20 |
+
// (Not the 'admin' store view, which represents admin panel)
|
21 |
+
$groups = Mage::app()->getGroups(false);
|
22 |
+
/** @var $group Mage_Core_Model_Store_Group */
|
23 |
+
foreach ($groups as $group) {
|
24 |
+
try {
|
25 |
+
if (Mage::getStoreConfig('bazaarvoice/SmartSEOFeed/EnableSmartSEO', $group->getDefaultStoreId()) === '1'
|
26 |
+
&& Mage::getStoreConfig('bazaarvoice/general/enable_bv', $group->getDefaultStoreId()) === '1') {
|
27 |
+
if(count($group->getStores()) > 0) {
|
28 |
+
Mage::log(' BV - Importing Smart SEO feed for store group: ' . $group->getName(), Zend_Log::INFO);
|
29 |
+
$this->retrieveSmartSEOPackageForStoreGroup($group);
|
30 |
+
}
|
31 |
+
else {
|
32 |
+
Mage::throwException('No stores for store group: ' . $group->getName());
|
33 |
+
}
|
34 |
+
}
|
35 |
+
else {
|
36 |
+
Mage::log(' BV - Smart SEO feed disabled for store group: ' . $group->getName(), Zend_Log::INFO);
|
37 |
+
}
|
38 |
+
} catch (Exception $e) {
|
39 |
+
Mage::log(' BV - Failed to import Smart SEO feed for store group: ' . $group->getName(), Zend_Log::ERR);
|
40 |
+
Mage::log(' BV - Error message: ' . $e->getMessage(), Zend_Log::ERR);
|
41 |
+
Mage::logException($e);
|
42 |
+
// Continue processing other store groups
|
43 |
+
}
|
44 |
+
}
|
45 |
+
// Log
|
46 |
+
Mage::log('End Bazaarvoice Smart SEO feed import');
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
*
|
51 |
+
* @param Mage_Core_Model_Store_Group $group Store Group
|
52 |
+
*
|
53 |
+
*/
|
54 |
+
public function retrieveSmartSEOPackageForStoreGroup($group)
|
55 |
+
{
|
56 |
+
if (Mage::getStoreConfig('bazaarvoice/SmartSEOFeed/EnableSmartSEO', $group->getDefaultStoreId()) === '1') {
|
57 |
+
|
58 |
+
$localFilePath = Mage::getBaseDir('var') . DS . 'import' . DS . 'bvfeeds';
|
59 |
+
$localExtractsPath = $localFilePath . DS . 'bvsmartseo-' . $group->getGroupId();
|
60 |
+
|
61 |
+
$gzLocalFilename = Mage::getStoreConfig('bazaarvoice/SmartSEOFeed/FeedFileName', $group->getDefaultStoreId());
|
62 |
+
// Hard code path to feed file
|
63 |
+
$remoteFile = '/feeds/' . Mage::getStoreConfig('bazaarvoice/SmartSEOFeed/FeedFileName', $group->getDefaultStoreId());
|
64 |
+
|
65 |
+
// Make sure the $remoteFile is tar.gz and not .zip (BV can create either - but Magento has no ability to deal with .zip)
|
66 |
+
$desiredExt = '.tar.gz';
|
67 |
+
if (substr_compare($remoteFile, $desiredExt, -strlen($desiredExt), strlen($desiredExt)) !== 0) {
|
68 |
+
$msg = 'BV - Unable to retrieve and process a .zip SmartSEO feed. Only .tar.gz SmartSEO feeds can be processed by this extension';
|
69 |
+
Mage::log($msg);
|
70 |
+
Mage::throwException($msg);
|
71 |
+
}
|
72 |
+
|
73 |
+
$gzInterface = new Mage_Archive_Gz();
|
74 |
+
$tarInterface = new Mage_Archive_Tar();
|
75 |
+
|
76 |
+
// Clear away any previous download that may have existed.
|
77 |
+
if (file_exists($localFilePath . DS . $gzLocalFilename)) {
|
78 |
+
unlink($localFilePath . DS . $gzLocalFilename);
|
79 |
+
}
|
80 |
+
|
81 |
+
// Download the file
|
82 |
+
if (!Mage::helper('bazaarvoice')->downloadFile($localFilePath, $gzLocalFilename, $remoteFile)) {
|
83 |
+
// Unable to download the file.
|
84 |
+
|
85 |
+
if (!file_exists($localExtractsPath)) {
|
86 |
+
// Couldn't download the file and no old SmartSEO files already exist on the filesystem
|
87 |
+
$subject = 'Bazaarvoice SmartSEO Content Unavailable';
|
88 |
+
$msg = 'The Bazaarvoice extension in your Magento store was unable to download new SmartSEO files from the Bazaarvoice server and there were no pre-existing SmartSEO files already in your Magento store.';
|
89 |
+
Mage::helper('bazaarvoice')->sendNotificationEmail($subject, $msg);
|
90 |
+
Mage::log($msg);
|
91 |
+
Mage::throwException($msg);
|
92 |
+
}
|
93 |
+
|
94 |
+
|
95 |
+
$lastModificationTime = filemtime($localExtractsPath); // num seconds since EPOCH
|
96 |
+
// Hard code maximum stale days
|
97 |
+
$maxStaleDays = 5;
|
98 |
+
if ((time() - $lastModificationTime) > ($maxStaleDays * 24 * 60 * 60)) {
|
99 |
+
// Couldn't download the file, and the old files that we DO have are too old.
|
100 |
+
$ioObject = new Varien_Io_File();
|
101 |
+
$ioObject->rmdir($localExtractsPath, true); // The 'true' indicates recursive delete
|
102 |
+
|
103 |
+
$subject = 'Bazaarvoice SmartSEO Content Unavailable';
|
104 |
+
$msg = 'The Bazaarvoice extension in your Magento store was unable to download new SmartSEO files from the Bazaarvoice server and the existing SmartSEO files that are already in the Magento store have expired.';
|
105 |
+
Mage::helper('bazaarvoice')->sendNotificationEmail($subject, $msg);
|
106 |
+
Mage::log($msg);
|
107 |
+
Mage::throwException($msg);
|
108 |
+
} else {
|
109 |
+
// Couldn't download the file, but the old files that we already have are still usable
|
110 |
+
$subject = "Bazaarvoice SmartSEO Content Couldn't be Updated";
|
111 |
+
$msg = 'The Bazaarvoice extension in your Magento store was unable to download new SmartSEO files from the Bazaarvoice server. The existing files will continue to be used.';
|
112 |
+
Mage::helper('bazaarvoice')->sendNotificationEmail($subject, $msg);
|
113 |
+
Mage::log($msg);
|
114 |
+
Mage::throwException($msg);
|
115 |
+
}
|
116 |
+
|
117 |
+
} else {
|
118 |
+
// Successfully downloaded the file.
|
119 |
+
|
120 |
+
// Clear out the existing extracts and recreate the dir.
|
121 |
+
$ioObject = new Varien_Io_File();
|
122 |
+
$ioObject->rmdir($localExtractsPath, true); // The 'true' indicates recursive delete
|
123 |
+
$ioObject->mkdir($localExtractsPath);
|
124 |
+
|
125 |
+
// Move the archive into the extracts folder. Use the native PHP function instead of Varien_Io_File
|
126 |
+
// since Varien_Io_File throws unnecessary warnings attempting to change working directories
|
127 |
+
rename($localFilePath . DS . $gzLocalFilename, $localExtractsPath . DS . $gzLocalFilename);
|
128 |
+
|
129 |
+
// Decompress the file
|
130 |
+
$tmpTarFilename = 'smartseo-tmp.tar';
|
131 |
+
$gzInterface->unpack($localExtractsPath . DS . $gzLocalFilename, $localExtractsPath . DS . $tmpTarFilename);
|
132 |
+
unlink($localExtractsPath . DS . $gzLocalFilename);
|
133 |
+
|
134 |
+
// Expand the .tar archive
|
135 |
+
$tarInterface->unpack($localExtractsPath . DS . $tmpTarFilename, $localExtractsPath . DS);
|
136 |
+
unlink($localExtractsPath . DS . $tmpTarFilename);
|
137 |
+
}
|
138 |
+
|
139 |
+
}
|
140 |
+
|
141 |
+
}
|
142 |
+
|
143 |
+
}
|
app/code/local/Bazaarvoice/Connector/Model/Source/AuthenticationMethod.php
ADDED
@@ -0,0 +1,25 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Source model for authentication method
|
4 |
+
*/
|
5 |
+
class Bazaarvoice_Connector_Model_Source_AuthenticationMethod
|
6 |
+
{
|
7 |
+
|
8 |
+
const BV_HOSTED_AUTH = 'bv';
|
9 |
+
const MAGENTO_SITE_AUTH = 'magento';
|
10 |
+
|
11 |
+
public function toOptionArray()
|
12 |
+
{
|
13 |
+
return array(
|
14 |
+
array(
|
15 |
+
'value' => self::BV_HOSTED_AUTH,
|
16 |
+
'label' => Mage::helper('bazaarvoice')->__('BV Hosted Authentication')
|
17 |
+
),
|
18 |
+
array(
|
19 |
+
'value' => self::MAGENTO_SITE_AUTH,
|
20 |
+
'label' => Mage::helper('bazaarvoice')->__('Magento Site Authentication')
|
21 |
+
)
|
22 |
+
);
|
23 |
+
}
|
24 |
+
|
25 |
+
}
|
app/code/local/Bazaarvoice/Connector/Model/Source/Environment.php
ADDED
@@ -0,0 +1,18 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Bazaarvoice_Connector_Model_Source_Environment
|
4 |
+
{
|
5 |
+
public function toOptionArray()
|
6 |
+
{
|
7 |
+
return array(
|
8 |
+
array(
|
9 |
+
'value' => 'staging',
|
10 |
+
'label' => Mage::helper('bazaarvoice')->__('Staging')
|
11 |
+
),
|
12 |
+
array(
|
13 |
+
'value' => 'production',
|
14 |
+
'label' => Mage::helper('bazaarvoice')->__('Production')
|
15 |
+
),
|
16 |
+
);
|
17 |
+
}
|
18 |
+
}
|
app/code/local/Bazaarvoice/Connector/Model/Source/FeedGenerationScope.php
ADDED
@@ -0,0 +1,30 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Source model for feed gen scope
|
4 |
+
*/
|
5 |
+
class Bazaarvoice_Connector_Model_Source_FeedGenerationScope
|
6 |
+
{
|
7 |
+
|
8 |
+
const SCOPE_WEBSITE = 'website';
|
9 |
+
const SCOPE_STORE_GROUP = 'group';
|
10 |
+
const SCOPE_STORE_VIEW = 'view';
|
11 |
+
|
12 |
+
public function toOptionArray()
|
13 |
+
{
|
14 |
+
return array(
|
15 |
+
array(
|
16 |
+
'value' => self::SCOPE_WEBSITE,
|
17 |
+
'label' => Mage::helper('bazaarvoice')->__('Magento Website')
|
18 |
+
),
|
19 |
+
array(
|
20 |
+
'value' => self::SCOPE_STORE_GROUP,
|
21 |
+
'label' => Mage::helper('bazaarvoice')->__('Magento Store / Store Group')
|
22 |
+
),
|
23 |
+
array(
|
24 |
+
'value' => self::SCOPE_STORE_VIEW,
|
25 |
+
'label' => Mage::helper('bazaarvoice')->__('Magento Store View')
|
26 |
+
),
|
27 |
+
);
|
28 |
+
}
|
29 |
+
|
30 |
+
}
|
app/code/local/Bazaarvoice/Connector/Model/Source/TriggeringEvent.php
ADDED
@@ -0,0 +1,25 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Source model for purchase feed triggering event
|
4 |
+
*/
|
5 |
+
class Bazaarvoice_Connector_Model_Source_TriggeringEvent
|
6 |
+
{
|
7 |
+
|
8 |
+
const PURCHASE = 'purchase';
|
9 |
+
const SHIPPING = 'shipping';
|
10 |
+
|
11 |
+
public function toOptionArray()
|
12 |
+
{
|
13 |
+
return array(
|
14 |
+
array(
|
15 |
+
'value' => self::SHIPPING,
|
16 |
+
'label' => Mage::helper('bazaarvoice')->__('Shipping')
|
17 |
+
),
|
18 |
+
array(
|
19 |
+
'value' => self::PURCHASE,
|
20 |
+
'label' => Mage::helper('bazaarvoice')->__('Purchase')
|
21 |
+
)
|
22 |
+
);
|
23 |
+
}
|
24 |
+
|
25 |
+
}
|
app/code/local/Bazaarvoice/Connector/controllers/FeedController.php
ADDED
@@ -0,0 +1,50 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
class Bazaarvoice_Connector_FeedController extends Mage_Core_Controller_Front_Action
|
3 |
+
{
|
4 |
+
public function preDispatch()
|
5 |
+
{
|
6 |
+
parent::preDispatch();
|
7 |
+
if ($this->getRequest()->getParam('bvauthenticateuser') == 'true') {
|
8 |
+
if (!Mage::getSingleton('customer/session')->authenticate($this)) {
|
9 |
+
$this->setFlag('', self::FLAG_NO_DISPATCH, true);
|
10 |
+
}
|
11 |
+
}
|
12 |
+
}
|
13 |
+
|
14 |
+
public function inlineratingsAction()
|
15 |
+
{
|
16 |
+
$rerf = Mage::getModel('bazaarvoice/retrieveInlineRatingsFeed');
|
17 |
+
$rerf->retrieveInlineRatingsFeed();
|
18 |
+
|
19 |
+
$this->loadLayout();
|
20 |
+
$this->renderLayout();
|
21 |
+
}
|
22 |
+
|
23 |
+
public function productAction()
|
24 |
+
{
|
25 |
+
$epf = Mage::getModel('bazaarvoice/exportProductFeed');
|
26 |
+
$epf->exportDailyProductFeed();
|
27 |
+
|
28 |
+
$this->loadLayout();
|
29 |
+
$this->renderLayout();
|
30 |
+
}
|
31 |
+
|
32 |
+
public function smartseoAction()
|
33 |
+
{
|
34 |
+
$seo = Mage::getModel('bazaarvoice/retrieveSmartSEOPackage');
|
35 |
+
$seo->retrieveSmartSEOPackage();
|
36 |
+
|
37 |
+
$this->loadLayout();
|
38 |
+
$this->renderLayout();
|
39 |
+
}
|
40 |
+
|
41 |
+
public function ppeAction()
|
42 |
+
{
|
43 |
+
$ppe = Mage::getModel('bazaarvoice/exportPurchaseFeed');
|
44 |
+
$ppe->exportPurchaseFeed();
|
45 |
+
|
46 |
+
$this->loadLayout();
|
47 |
+
$this->renderLayout();
|
48 |
+
}
|
49 |
+
|
50 |
+
}
|
app/code/local/Bazaarvoice/Connector/controllers/IndexController.php
ADDED
@@ -0,0 +1,25 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
class Bazaarvoice_Connector_IndexController extends Mage_Core_Controller_Front_Action
|
3 |
+
{
|
4 |
+
public function preDispatch()
|
5 |
+
{
|
6 |
+
parent::preDispatch();
|
7 |
+
if ($this->getRequest()->getParam('bvauthenticateuser') == 'true') {
|
8 |
+
if (!Mage::getSingleton('customer/session')->authenticate($this)) {
|
9 |
+
$this->setFlag('', self::FLAG_NO_DISPATCH, true);
|
10 |
+
}
|
11 |
+
}
|
12 |
+
}
|
13 |
+
|
14 |
+
public function indexAction()
|
15 |
+
{
|
16 |
+
if(Mage::getStoreConfig('bazaarvoice/general/enable_bv') === '1') {
|
17 |
+
$this->loadLayout();
|
18 |
+
$this->renderLayout();
|
19 |
+
}
|
20 |
+
else {
|
21 |
+
// Send customer to 404 page
|
22 |
+
$this->_forward('defaultNoRoute');
|
23 |
+
}
|
24 |
+
}
|
25 |
+
}
|
app/code/local/Bazaarvoice/Connector/etc/adminhtml.xml
ADDED
@@ -0,0 +1,25 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<config>
|
3 |
+
<acl>
|
4 |
+
<resources>
|
5 |
+
<all>
|
6 |
+
<title>Allow Everything</title>
|
7 |
+
</all>
|
8 |
+
<admin>
|
9 |
+
<children>
|
10 |
+
<system>
|
11 |
+
<children>
|
12 |
+
<config>
|
13 |
+
<children>
|
14 |
+
<bazaarvoice>
|
15 |
+
<title>Bazaarvoice</title>
|
16 |
+
</bazaarvoice>
|
17 |
+
</children>
|
18 |
+
</config>
|
19 |
+
</children>
|
20 |
+
</system>
|
21 |
+
</children>
|
22 |
+
</admin>
|
23 |
+
</resources>
|
24 |
+
</acl>
|
25 |
+
</config>
|
app/code/local/Bazaarvoice/Connector/etc/config.xml
ADDED
@@ -0,0 +1,159 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<!--
|
3 |
+
/**
|
4 |
+
* @category BV
|
5 |
+
* @package Bazaarvoice
|
6 |
+
*/
|
7 |
+
-->
|
8 |
+
<config>
|
9 |
+
<modules>
|
10 |
+
<Bazaarvoice_Connector>
|
11 |
+
<version>6.0.3</version>
|
12 |
+
<depends>
|
13 |
+
<!-- no dependencies -->
|
14 |
+
</depends>
|
15 |
+
</Bazaarvoice_Connector>
|
16 |
+
</modules>
|
17 |
+
|
18 |
+
<global>
|
19 |
+
<models>
|
20 |
+
<bazaarvoice>
|
21 |
+
<class>Bazaarvoice_Connector_Model</class>
|
22 |
+
</bazaarvoice>
|
23 |
+
</models>
|
24 |
+
<blocks>
|
25 |
+
<bazaarvoice>
|
26 |
+
<class>Bazaarvoice_Connector_Block</class>
|
27 |
+
</bazaarvoice>
|
28 |
+
</blocks>
|
29 |
+
<helpers>
|
30 |
+
<bazaarvoice>
|
31 |
+
<class>Bazaarvoice_Connector_Helper</class>
|
32 |
+
</bazaarvoice>
|
33 |
+
</helpers>
|
34 |
+
<template>
|
35 |
+
<email>
|
36 |
+
<bazaarvoice_notification_template module="bazaarvoice">
|
37 |
+
<label>Bazaarvoice Notifications</label>
|
38 |
+
<file>bazaarvoice_notification.html</file>
|
39 |
+
<type>text</type>
|
40 |
+
</bazaarvoice_notification_template>
|
41 |
+
</email>
|
42 |
+
</template>
|
43 |
+
<resources>
|
44 |
+
<bazaarvoice_setup>
|
45 |
+
<setup>
|
46 |
+
<module>Bazaarvoice_Connector</module>
|
47 |
+
<class>Bazaarvoice_Connector_Model_Mysql4_Setup</class>
|
48 |
+
</setup>
|
49 |
+
<connection>
|
50 |
+
<use>core_setup</use>
|
51 |
+
</connection>
|
52 |
+
</bazaarvoice_setup>
|
53 |
+
</resources>
|
54 |
+
</global>
|
55 |
+
|
56 |
+
<frontend>
|
57 |
+
<product>
|
58 |
+
<collection>
|
59 |
+
<attributes>
|
60 |
+
<bv_average_rating />
|
61 |
+
<bv_review_count />
|
62 |
+
<bv_rating_range />
|
63 |
+
</attributes>
|
64 |
+
</collection>
|
65 |
+
</product>
|
66 |
+
<routers>
|
67 |
+
<bazaarvoice>
|
68 |
+
<use>standard</use>
|
69 |
+
<args>
|
70 |
+
<module>Bazaarvoice_Connector</module>
|
71 |
+
<frontName>bazaarvoice</frontName>
|
72 |
+
</args>
|
73 |
+
</bazaarvoice>
|
74 |
+
</routers>
|
75 |
+
<layout>
|
76 |
+
<updates>
|
77 |
+
<bazaarvoice>
|
78 |
+
<file>bazaarvoice.xml</file>
|
79 |
+
</bazaarvoice>
|
80 |
+
</updates>
|
81 |
+
</layout>
|
82 |
+
</frontend>
|
83 |
+
|
84 |
+
<crontab>
|
85 |
+
<jobs>
|
86 |
+
<bazaarvoice_product_feed>
|
87 |
+
<schedule>
|
88 |
+
<cron_expr>0 1 * * *</cron_expr><!-- Every day at 1:00 AM -->
|
89 |
+
</schedule>
|
90 |
+
<run>
|
91 |
+
<model>bazaarvoice/exportProductFeed::exportDailyProductFeed</model>
|
92 |
+
</run>
|
93 |
+
</bazaarvoice_product_feed>
|
94 |
+
<bazaarvoice_purchase_feed>
|
95 |
+
<schedule>
|
96 |
+
<cron_expr>30 2 * * 6</cron_expr><!-- Every Saturday at 2:30 AM -->
|
97 |
+
</schedule>
|
98 |
+
<run>
|
99 |
+
<model>bazaarvoice/exportPurchaseFeed::exportPurchaseFeed</model>
|
100 |
+
</run>
|
101 |
+
</bazaarvoice_purchase_feed>
|
102 |
+
</jobs>
|
103 |
+
</crontab>
|
104 |
+
|
105 |
+
<default>
|
106 |
+
<bazaarvoice>
|
107 |
+
<general>
|
108 |
+
<enable_bv>0</enable_bv>
|
109 |
+
<environment>staging</environment>
|
110 |
+
<authentication_method>bv</authentication_method>
|
111 |
+
<enable_roibeacon>1</enable_roibeacon>
|
112 |
+
</general>
|
113 |
+
<rr>
|
114 |
+
<enable_rr>1</enable_rr>
|
115 |
+
<do_show_content_js><![CDATA[
|
116 |
+
// If the container is hidden (such as behind a tab), put code here to make it visible (open the tab).
|
117 |
+
]]></do_show_content_js>
|
118 |
+
<enable_inline_ratings>1</enable_inline_ratings>
|
119 |
+
</rr>
|
120 |
+
<qa>
|
121 |
+
<enable_qa>1</enable_qa>
|
122 |
+
<do_show_content_js><![CDATA[
|
123 |
+
// If the container is hidden (such as behind a tab), put code here to make it visible (open the tab).
|
124 |
+
]]></do_show_content_js>
|
125 |
+
</qa>
|
126 |
+
<feeds>
|
127 |
+
<enable_product_feed>1</enable_product_feed>
|
128 |
+
<enable_purchase_feed>1</enable_purchase_feed>
|
129 |
+
<triggering_event>shipping</triggering_event>
|
130 |
+
<generation_scope>website</generation_scope>
|
131 |
+
</feeds>
|
132 |
+
|
133 |
+
<!-- These config settings are intended to be overriden with installation-specific values in
|
134 |
+
app/etc/local.xml file -->
|
135 |
+
<bv_config>
|
136 |
+
<!-- Hard code export path and filename in class constants -->
|
137 |
+
<product_feed_export_filename>productfeed.xml</product_feed_export_filename>
|
138 |
+
<!-- Hard code export path and filename in class constants -->
|
139 |
+
<product_feed_export_export_path>/import-inbox</product_feed_export_export_path>
|
140 |
+
<!-- Magento Brand Attribute Code
|
141 |
+
The following attribute code will be used to locate the brand of products
|
142 |
+
which is sent in the product feed: -->
|
143 |
+
<product_feed_brand_attribute_code></product_feed_brand_attribute_code>
|
144 |
+
|
145 |
+
<!-- If true, use Magento category URL path as category id, otherwise use Mage category entity primary key -->
|
146 |
+
<category_id_use_url_path>true</category_id_use_url_path>
|
147 |
+
|
148 |
+
<!-- FTP Connection Host Name. If this is not specified, the standard ftp-stg.bazaarvoice.com and
|
149 |
+
ftp.bazaarvoice.com will be used -->
|
150 |
+
<ftp_host_name></ftp_host_name>
|
151 |
+
|
152 |
+
<!-- Display code - We still need this for some clients -->
|
153 |
+
<display_code></display_code>
|
154 |
+
</bv_config>
|
155 |
+
</bazaarvoice>
|
156 |
+
</default>
|
157 |
+
|
158 |
+
|
159 |
+
</config>
|
app/code/local/Bazaarvoice/Connector/etc/system.xml
ADDED
@@ -0,0 +1,300 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<config>
|
3 |
+
<sections>
|
4 |
+
<bazaarvoice translate="label">
|
5 |
+
<label>Bazaarvoice</label>
|
6 |
+
<tab>general</tab>
|
7 |
+
<frontend_type>text</frontend_type>
|
8 |
+
<sort_order>1000</sort_order>
|
9 |
+
<show_in_default>1</show_in_default>
|
10 |
+
<show_in_website>1</show_in_website>
|
11 |
+
<show_in_store>1</show_in_store>
|
12 |
+
<groups>
|
13 |
+
<general translate="label">
|
14 |
+
<label>General</label>
|
15 |
+
<frontend_type>text</frontend_type>
|
16 |
+
<sort_order>100</sort_order>
|
17 |
+
<show_in_default>1</show_in_default>
|
18 |
+
<show_in_website>1</show_in_website>
|
19 |
+
<show_in_store>1</show_in_store>
|
20 |
+
<fields>
|
21 |
+
<enable_bv>
|
22 |
+
<label>Enable Bazaarvoice Extension</label>
|
23 |
+
<frontend_type>select</frontend_type>
|
24 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
25 |
+
<comment><![CDATA[Enable all Bazaarvoice Magento extension features at this Magento Scope]]></comment>
|
26 |
+
<sort_order>1</sort_order>
|
27 |
+
<show_in_default>1</show_in_default>
|
28 |
+
<show_in_website>1</show_in_website>
|
29 |
+
<show_in_store>1</show_in_store>
|
30 |
+
</enable_bv>
|
31 |
+
<environment>
|
32 |
+
<label>Environment</label>
|
33 |
+
<frontend_type>select</frontend_type>
|
34 |
+
<source_model>bazaarvoice/source_environment</source_model>
|
35 |
+
<comment><![CDATA[BV environment that this Magento scope is integrating with]]></comment>
|
36 |
+
<sort_order>10</sort_order>
|
37 |
+
<show_in_default>1</show_in_default>
|
38 |
+
<show_in_website>1</show_in_website>
|
39 |
+
<show_in_store>1</show_in_store>
|
40 |
+
</environment>
|
41 |
+
<client_name translate="label comment">
|
42 |
+
<label>Client Name</label>
|
43 |
+
<frontend_type>text</frontend_type>
|
44 |
+
<comment><![CDATA[Client Name as defined in your BV platform account]]></comment>
|
45 |
+
<sort_order>14</sort_order>
|
46 |
+
<show_in_default>1</show_in_default>
|
47 |
+
<show_in_website>1</show_in_website>
|
48 |
+
<show_in_store>1</show_in_store>
|
49 |
+
</client_name>
|
50 |
+
<ftp_password>
|
51 |
+
<label>FTP Password</label>
|
52 |
+
<frontend_type>text</frontend_type>
|
53 |
+
<comment><![CDATA[Password used to access the BV FTP server for feed upload/download processes.]]></comment>
|
54 |
+
<sort_order>15</sort_order>
|
55 |
+
<show_in_default>1</show_in_default>
|
56 |
+
<show_in_website>1</show_in_website>
|
57 |
+
<show_in_store>1</show_in_store>
|
58 |
+
</ftp_password>
|
59 |
+
<!-- Site Auth Disabled for now -->
|
60 |
+
<!--
|
61 |
+
<authentication_method>
|
62 |
+
<label>Authentication Method</label>
|
63 |
+
<frontend_type>select</frontend_type>
|
64 |
+
<comment><![CDATA[With BV Hosted authentication method, users click the "write a review" link on a product page and authenticate by using just their email address provided in content submission page. With Magento Site authentication, users are redirected to login to the Magento site before the user can access the BV submission page.]]></comment>
|
65 |
+
<source_model>bazaarvoice/source_authenticationMethod</source_model>
|
66 |
+
<sort_order>17</sort_order>
|
67 |
+
<show_in_default>1</show_in_default>
|
68 |
+
<show_in_website>1</show_in_website>
|
69 |
+
<show_in_store>1</show_in_store>
|
70 |
+
</authentication_method>
|
71 |
+
<shared_encoding_key>
|
72 |
+
<label>Shared Encoding Key</label>
|
73 |
+
<frontend_type>text</frontend_type>
|
74 |
+
<comment><![CDATA[Key used to encode BV user authentication string. Only required when Magento Site Authentication is selected. Defined in your BV platform account.]]></comment>
|
75 |
+
<sort_order>18</sort_order>
|
76 |
+
<show_in_default>1</show_in_default>
|
77 |
+
<show_in_website>1</show_in_website>
|
78 |
+
<show_in_store>1</show_in_store>
|
79 |
+
</shared_encoding_key>
|
80 |
+
-->
|
81 |
+
<deployment_zone>
|
82 |
+
<label>Deployment Zone</label>
|
83 |
+
<frontend_type>text</frontend_type>
|
84 |
+
<comment><![CDATA[Deployment Zone Name as defined in your BV platform account]]></comment>
|
85 |
+
<sort_order>20</sort_order>
|
86 |
+
<show_in_default>1</show_in_default>
|
87 |
+
<show_in_website>1</show_in_website>
|
88 |
+
<show_in_store>1</show_in_store>
|
89 |
+
</deployment_zone>
|
90 |
+
<locale>
|
91 |
+
<label>Locale</label>
|
92 |
+
<frontend_type>text</frontend_type>
|
93 |
+
<comment>
|
94 |
+
<![CDATA[The BV locale for this Magento Configuration Scope. For example: "en_US". The locale must be enabled within your BV platform account.]]></comment>
|
95 |
+
<sort_order>21</sort_order>
|
96 |
+
<show_in_default>1</show_in_default>
|
97 |
+
<show_in_website>1</show_in_website>
|
98 |
+
<show_in_store>1</show_in_store>
|
99 |
+
</locale>
|
100 |
+
<!-- Site Auth Disabled for now -->
|
101 |
+
<!--
|
102 |
+
<submission_url>
|
103 |
+
<label>Submission Container URL</label>
|
104 |
+
<frontend_type>text</frontend_type>
|
105 |
+
<comment><![CDATA[The URL of the Bazaarvoice submission page. This extension provides a submission container page, located at the "bazaarvoice" context root. For example: http://yourdomain.com/magento/bazaarvoice]]></comment>
|
106 |
+
<sort_order>60</sort_order>
|
107 |
+
<show_in_default>1</show_in_default>
|
108 |
+
<show_in_website>1</show_in_website>
|
109 |
+
<show_in_store>1</show_in_store>
|
110 |
+
</submission_url>
|
111 |
+
-->
|
112 |
+
<enable_cloud_seo>
|
113 |
+
<label>Enable Cloud SEO</label>
|
114 |
+
<frontend_type>select</frontend_type>
|
115 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
116 |
+
<comment>
|
117 |
+
<![CDATA[Turn on the BV SEO solution. This will include SEO-friendly content (located in the BV SEO cloud) in your product pages. See documentation for additional steps that must be completed for this feature to take effect.]]></comment>
|
118 |
+
<sort_order>80</sort_order>
|
119 |
+
<show_in_default>1</show_in_default>
|
120 |
+
<show_in_website>1</show_in_website>
|
121 |
+
<show_in_store>1</show_in_store>
|
122 |
+
</enable_cloud_seo>
|
123 |
+
<cloud_seo_key>
|
124 |
+
<label>Cloud SEO Key</label>
|
125 |
+
<frontend_type>text</frontend_type>
|
126 |
+
<comment>
|
127 |
+
<![CDATA[SEO Cloud key value as defined in your BV platform account. This key is only required if Cloud SEO is enabled.]]></comment>
|
128 |
+
<sort_order>90</sort_order>
|
129 |
+
<show_in_default>1</show_in_default>
|
130 |
+
<show_in_website>1</show_in_website>
|
131 |
+
<show_in_store>1</show_in_store>
|
132 |
+
</cloud_seo_key>
|
133 |
+
<enable_roibeacon>
|
134 |
+
<label>Enable ROI Beacon</label>
|
135 |
+
<frontend_type>select</frontend_type>
|
136 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
137 |
+
<comment>
|
138 |
+
<![CDATA[Turn on the BV ROI beacon tag on the purchase transaction (checkout) page. See documentation for additional steps that must be completed for this feature to take effect.]]></comment>
|
139 |
+
<sort_order>100</sort_order>
|
140 |
+
<show_in_default>1</show_in_default>
|
141 |
+
<show_in_website>1</show_in_website>
|
142 |
+
<show_in_store>1</show_in_store>
|
143 |
+
</enable_roibeacon>
|
144 |
+
</fields>
|
145 |
+
</general>
|
146 |
+
<rr translate="label">
|
147 |
+
<label>Ratings and Reviews</label>
|
148 |
+
<frontend_type>text</frontend_type>
|
149 |
+
<sort_order>110</sort_order>
|
150 |
+
<show_in_default>1</show_in_default>
|
151 |
+
<show_in_website>1</show_in_website>
|
152 |
+
<show_in_store>1</show_in_store>
|
153 |
+
<fields>
|
154 |
+
<enable_rr>
|
155 |
+
<label>Enable Ratings & Reviews</label>
|
156 |
+
<frontend_type>select</frontend_type>
|
157 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
158 |
+
<comment>
|
159 |
+
<![CDATA[Turn on BV Ratings & Reviews. This will enable display of R&R content on your product pages. See documentation for additional steps that must be completed for this feature to take effect.]]></comment>
|
160 |
+
<sort_order>10</sort_order>
|
161 |
+
<show_in_default>1</show_in_default>
|
162 |
+
<show_in_website>1</show_in_website>
|
163 |
+
<show_in_store>1</show_in_store>
|
164 |
+
</enable_rr>
|
165 |
+
<do_show_content_js>
|
166 |
+
<label>JS Callback function to display R&R content (doShowContent)</label>
|
167 |
+
<frontend_type>textarea</frontend_type>
|
168 |
+
<comment><![CDATA[The Bazaarvoice doShowContent javascript callback is triggered when the "read all reviews" link in the review summary is clicked.
|
169 |
+
You may provide code here that you wish to execute on said click event. For example, you may want to activate a specific tab on the page. This
|
170 |
+
code will be wrapped in a javascript function(){...} block. See your Bazaarvoice Implementation manual for further information.]]></comment>
|
171 |
+
<sort_order>20</sort_order>
|
172 |
+
<show_in_default>1</show_in_default>
|
173 |
+
<show_in_website>1</show_in_website>
|
174 |
+
<show_in_store>1</show_in_store>
|
175 |
+
</do_show_content_js>
|
176 |
+
<enable_inline_ratings>
|
177 |
+
<label>Enable Hosted Inline Ratings</label>
|
178 |
+
<frontend_type>select</frontend_type>
|
179 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
180 |
+
<comment>
|
181 |
+
<![CDATA[Turn on BV Hosted inline ratings. This will enable display of product rating statistics on your category and search results pages. See documentation for additional steps that must be completed for this feature to take effect.]]></comment>
|
182 |
+
<sort_order>30</sort_order>
|
183 |
+
<show_in_default>1</show_in_default>
|
184 |
+
<show_in_website>1</show_in_website>
|
185 |
+
<show_in_store>1</show_in_store>
|
186 |
+
</enable_inline_ratings>
|
187 |
+
</fields>
|
188 |
+
</rr>
|
189 |
+
<qa translate="label">
|
190 |
+
<label>Questions and Answers</label>
|
191 |
+
<frontend_type>text</frontend_type>
|
192 |
+
<sort_order>120</sort_order>
|
193 |
+
<show_in_default>1</show_in_default>
|
194 |
+
<show_in_website>1</show_in_website>
|
195 |
+
<show_in_store>1</show_in_store>
|
196 |
+
<fields>
|
197 |
+
<enable_qa>
|
198 |
+
<label>Enable Questions & Answers</label>
|
199 |
+
<frontend_type>select</frontend_type>
|
200 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
201 |
+
<comment>
|
202 |
+
<![CDATA[Turn on BV Questions & Answers. This will enable display of Q&A content on your product pages. See documentation for additional steps that must be completed for this feature to take effect.]]></comment>
|
203 |
+
<sort_order>10</sort_order>
|
204 |
+
<show_in_default>1</show_in_default>
|
205 |
+
<show_in_website>1</show_in_website>
|
206 |
+
<show_in_store>1</show_in_store>
|
207 |
+
</enable_qa>
|
208 |
+
<do_show_content_js>
|
209 |
+
<label>JS Callback function to display Q&A content (doShowContent)(Product Page)</label>
|
210 |
+
<frontend_type>textarea</frontend_type>
|
211 |
+
<comment><![CDATA[The Bazaarvoice doShowContent javascript callback is triggered when the "read all Q&A" link in the question/answer summary is clicked.
|
212 |
+
You may provide code here that you wish to execute on said click event. For example, you may want to activate a specific tab on the page. This
|
213 |
+
code will be wrapped in a javascript function(){...} block. See your Bazaarvoice Implementation manual for further information.]]></comment>
|
214 |
+
<sort_order>70</sort_order>
|
215 |
+
<show_in_default>1</show_in_default>
|
216 |
+
<show_in_website>1</show_in_website>
|
217 |
+
<show_in_store>1</show_in_store>
|
218 |
+
</do_show_content_js>
|
219 |
+
</fields>
|
220 |
+
</qa>
|
221 |
+
<!-- Temp disable as part of MGP-103
|
222 |
+
<InlineRatingFeed translate="label">
|
223 |
+
<label>Inline Ratings Feed Import</label>
|
224 |
+
<frontend_type>text</frontend_type>
|
225 |
+
<sort_order>160</sort_order>
|
226 |
+
<show_in_default>1</show_in_default>
|
227 |
+
<show_in_website>1</show_in_website>
|
228 |
+
<show_in_store>1</show_in_store>
|
229 |
+
<fields>
|
230 |
+
</fields>
|
231 |
+
</InlineRatingFeed>
|
232 |
+
-->
|
233 |
+
<feeds translate="label">
|
234 |
+
<label>Feeds</label>
|
235 |
+
<frontend_type>text</frontend_type>
|
236 |
+
<sort_order>200</sort_order>
|
237 |
+
<show_in_default>1</show_in_default>
|
238 |
+
<show_in_website>1</show_in_website>
|
239 |
+
<show_in_store>1</show_in_store>
|
240 |
+
<fields>
|
241 |
+
<enable_product_feed>
|
242 |
+
<label>Enable Product Feed</label>
|
243 |
+
<frontend_type>select</frontend_type>
|
244 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
245 |
+
<comment>
|
246 |
+
<![CDATA[Turn on Product Feed generation. This will enable generation of a product feed to be sent to the BV FTP server. See documentation for additional steps to setup a scheduled job in Magento for this feature to take effect.]]></comment>
|
247 |
+
<sort_order>10</sort_order>
|
248 |
+
<show_in_default>1</show_in_default>
|
249 |
+
<show_in_website>1</show_in_website>
|
250 |
+
<show_in_store>1</show_in_store>
|
251 |
+
</enable_product_feed>
|
252 |
+
<enable_purchase_feed>
|
253 |
+
<label>Enable Purchase Feed</label>
|
254 |
+
<frontend_type>select</frontend_type>
|
255 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
256 |
+
<comment>
|
257 |
+
<![CDATA[Turn on Purchase Feed generation. This will enable generation of a purchase feed to be sent to the BV FTP server to be used to send post-interaction emails to your customers in order to solicit review submission. See documentation for additional steps to setup a scheduled job for this feature to take effect.]]></comment>
|
258 |
+
<sort_order>20</sort_order>
|
259 |
+
<show_in_default>1</show_in_default>
|
260 |
+
<show_in_website>1</show_in_website>
|
261 |
+
<show_in_store>1</show_in_store>
|
262 |
+
</enable_purchase_feed>
|
263 |
+
<triggering_event>
|
264 |
+
<label>Purchase Feed Triggering Event</label>
|
265 |
+
<frontend_type>select</frontend_type>
|
266 |
+
<comment>
|
267 |
+
<![CDATA[This determines whether to use the purchase date or ship date when calculating which purchases to include in the purchase feed.]]></comment>
|
268 |
+
<source_model>bazaarvoice/source_triggeringEvent</source_model>
|
269 |
+
<sort_order>30</sort_order>
|
270 |
+
<show_in_default>1</show_in_default>
|
271 |
+
<show_in_website>1</show_in_website>
|
272 |
+
<show_in_store>1</show_in_store>
|
273 |
+
</triggering_event>
|
274 |
+
<admin_email>
|
275 |
+
<label>Administrator Email</label>
|
276 |
+
<frontend_type>text</frontend_type>
|
277 |
+
<comment>
|
278 |
+
<![CDATA[All notifications for BV-related Magento job schedules will be sent to this email address.]]></comment>
|
279 |
+
<sort_order>70</sort_order>
|
280 |
+
<show_in_default>1</show_in_default>
|
281 |
+
<show_in_website>1</show_in_website>
|
282 |
+
<show_in_store>1</show_in_store>
|
283 |
+
</admin_email>
|
284 |
+
<generation_scope>
|
285 |
+
<label>Feed Generation Scope</label>
|
286 |
+
<frontend_type>select</frontend_type>
|
287 |
+
<comment>
|
288 |
+
<![CDATA[This determines whether separate feed files will be generated and sent to BV for each website, store or store view.]]></comment>
|
289 |
+
<source_model>bazaarvoice/source_feedGenerationScope</source_model>
|
290 |
+
<sort_order>90</sort_order>
|
291 |
+
<show_in_default>1</show_in_default>
|
292 |
+
<show_in_website>0</show_in_website>
|
293 |
+
<show_in_store>0</show_in_store>
|
294 |
+
</generation_scope>
|
295 |
+
</fields>
|
296 |
+
</feeds>
|
297 |
+
</groups>
|
298 |
+
</bazaarvoice>
|
299 |
+
</sections>
|
300 |
+
</config>
|
app/code/local/Bazaarvoice/Connector/sql/bazaarvoice_setup/mysql4-install-0.1.0.php
ADDED
@@ -0,0 +1,16 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
/* @var $installer Mage_Sales_Model_Mysql4_Setup */
|
3 |
+
$installer = $this;
|
4 |
+
|
5 |
+
$installer->startSetup();
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Adds an attribute of the code sent_in_bv_postpurchase_feed to the Order object.
|
9 |
+
* As this is a flat table, it adds the column to the table (SALES_FLAT_ORDER).
|
10 |
+
**/
|
11 |
+
|
12 |
+
Mage::log("BV: Installing v0.1.0");
|
13 |
+
$installer->addAttribute('order', Bazaarvoice_Connector_Model_ExportPurchaseFeed::ALREADY_SENT_IN_FEED_FLAG, array('type'=>'int'));
|
14 |
+
|
15 |
+
$installer->endSetup();
|
16 |
+
|
app/design/frontend/enterprise/default/layout/bazaarvoice.xml
ADDED
@@ -0,0 +1,131 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<layout version="0.1.0">
|
3 |
+
<default>
|
4 |
+
</default>
|
5 |
+
|
6 |
+
<!--
|
7 |
+
This is the submission container page for R&R and Q&A
|
8 |
+
It can be accessed at the root of your magento URL context. For example:
|
9 |
+
www.yourdomain.com/bazaarvoice (assuming magento runs your entire site)
|
10 |
+
or
|
11 |
+
www.yourdomain.com/magento/bazaarvoice
|
12 |
+
-->
|
13 |
+
<bazaarvoice_index_index>
|
14 |
+
<reference name="root">
|
15 |
+
<action method="setTemplate"><template>page/1column.phtml</template></action>
|
16 |
+
</reference>
|
17 |
+
<reference name="head">
|
18 |
+
<block type="bazaarvoice/bazaarvoice" name="headerincludes" template="bazaarvoice/display/headerincludes.phtml" after="-" />
|
19 |
+
<action method="setRobots"><value>noindex, nofollow</value></action>
|
20 |
+
</reference>
|
21 |
+
<reference name="content">
|
22 |
+
<block type="bazaarvoice/submissioncontainer" name="submissioncontainer" template="bazaarvoice/submit/submissioncontainer.phtml" />
|
23 |
+
</reference>
|
24 |
+
</bazaarvoice_index_index>
|
25 |
+
|
26 |
+
<!--
|
27 |
+
Set up BV content to be injectable on all product and category pages. Note that the head inclusion of bvapi.js will be
|
28 |
+
made on all pages, regardless of whether or not any other blocks are inserted into the template (like bv_reviews).
|
29 |
+
-->
|
30 |
+
<catalog_product_view>
|
31 |
+
<reference name="head">
|
32 |
+
<block type="bazaarvoice/bazaarvoice" name="headerincludes" template="bazaarvoice/display/headerincludes.phtml" after="-" />
|
33 |
+
<block type="bazaarvoice/bazaarvoice" name="headerproduct" template="bazaarvoice/display/headerproduct.phtml" after="headerincludes" />
|
34 |
+
</reference>
|
35 |
+
<reference name="content">
|
36 |
+
<reference name="product.info">
|
37 |
+
<block type="bazaarvoice/bazaarvoice" name="reviewsummary" as="bv_reviewsummary" template="bazaarvoice/display/rr/reviewsummary.phtml" />
|
38 |
+
<block type="bazaarvoice/reviews" name="reviews" as="bv_reviews" template="bazaarvoice/display/rr/reviews.phtml" />
|
39 |
+
|
40 |
+
<block type="bazaarvoice/bazaarvoice" name="questionsummary" as="bv_questionsummary" template="bazaarvoice/display/qa/questionsummary.phtml" />
|
41 |
+
<block type="bazaarvoice/bazaarvoice" name="questions" as="bv_questions" template="bazaarvoice/display/qa/questions.phtml" />
|
42 |
+
</reference>
|
43 |
+
</reference>
|
44 |
+
</catalog_product_view>
|
45 |
+
|
46 |
+
<catalog_category_default>
|
47 |
+
<reference name="head">
|
48 |
+
<block type="bazaarvoice/bazaarvoice" name="headerincludes" template="bazaarvoice/display/headerincludes.phtml" after="-" />
|
49 |
+
</reference>
|
50 |
+
<reference name="content">
|
51 |
+
<reference name="category.products">
|
52 |
+
<reference name="product_list" >
|
53 |
+
<block type="bazaarvoice/ratings" name="inline_ratings" as="inline_ratings" template="bazaarvoice/display/rr/ratings.phtml" />
|
54 |
+
</reference>
|
55 |
+
</reference>
|
56 |
+
</reference>
|
57 |
+
</catalog_category_default>
|
58 |
+
|
59 |
+
<catalog_category_layered>
|
60 |
+
<reference name="head">
|
61 |
+
<block type="bazaarvoice/bazaarvoice" name="headerincludes" template="bazaarvoice/display/headerincludes.phtml" after="-" />
|
62 |
+
</reference>
|
63 |
+
<reference name="content">
|
64 |
+
<reference name="category.products">
|
65 |
+
<reference name="product_list" >
|
66 |
+
<block type="bazaarvoice/ratings" name="inline_ratings" as="inline_ratings" template="bazaarvoice/display/rr/ratings.phtml" />
|
67 |
+
</reference>
|
68 |
+
</reference>
|
69 |
+
</reference>
|
70 |
+
</catalog_category_layered>
|
71 |
+
|
72 |
+
<catalogsearch_result_index>
|
73 |
+
<reference name="head">
|
74 |
+
<block type="bazaarvoice/bazaarvoice" name="headerincludes" template="bazaarvoice/display/headerincludes.phtml" after="-" />
|
75 |
+
</reference>
|
76 |
+
<reference name="content">
|
77 |
+
<reference name="search.result">
|
78 |
+
<reference name="search_result_list" >
|
79 |
+
<block type="bazaarvoice/ratings" name="inline_ratings" as="inline_ratings" template="bazaarvoice/display/rr/ratings.phtml" />
|
80 |
+
</reference>
|
81 |
+
</reference>
|
82 |
+
</reference>
|
83 |
+
</catalogsearch_result_index>
|
84 |
+
|
85 |
+
<catalogsearch_advanced_result>
|
86 |
+
<reference name="head">
|
87 |
+
<block type="bazaarvoice/bazaarvoice" name="headerincludes" template="bazaarvoice/display/headerincludes.phtml" after="-" />
|
88 |
+
</reference>
|
89 |
+
<reference name="content">
|
90 |
+
<reference name="catalogsearch_advanced_result">
|
91 |
+
<reference name="search_result_list" >
|
92 |
+
<block type="bazaarvoice/ratings" name="inline_ratings" as="inline_ratings" template="bazaarvoice/display/rr/ratings.phtml" />
|
93 |
+
</reference>
|
94 |
+
</reference>
|
95 |
+
</reference>
|
96 |
+
</catalogsearch_advanced_result>
|
97 |
+
|
98 |
+
<!--
|
99 |
+
The feed controller is used to more easily test/debug the feed generation or import. This should not be enabled in a production environment for security reasons.
|
100 |
+
-->
|
101 |
+
<!--
|
102 |
+
<bazaarvoice_feed_ppe>
|
103 |
+
<reference name="root">
|
104 |
+
<action method="setTemplate"><template>page/1column.phtml</template></action>
|
105 |
+
</reference>
|
106 |
+
</bazaarvoice_feed_ppe>
|
107 |
+
<bazaarvoice_feed_inlineratings>
|
108 |
+
<reference name="root">
|
109 |
+
<action method="setTemplate"><template>page/1column.phtml</template></action>
|
110 |
+
</reference>
|
111 |
+
</bazaarvoice_feed_inlineratings>
|
112 |
+
<bazaarvoice_feed_product>
|
113 |
+
<reference name="root">
|
114 |
+
<action method="setTemplate"><template>page/1column.phtml</template></action>
|
115 |
+
</reference>
|
116 |
+
</bazaarvoice_feed_product>
|
117 |
+
<bazaarvoice_feed_smartseo>
|
118 |
+
<reference name="root">
|
119 |
+
<action method="setTemplate"><template>page/1column.phtml</template></action>
|
120 |
+
</reference>
|
121 |
+
</bazaarvoice_feed_smartseo>
|
122 |
+
-->
|
123 |
+
|
124 |
+
<checkout_onepage_success>
|
125 |
+
<reference name="head">
|
126 |
+
<block type="bazaarvoice/bazaarvoice" template="bazaarvoice/display/headerincludes.phtml" after="-" />
|
127 |
+
<block type="bazaarvoice/roi_beacon" template="bazaarvoice/submit/roi_beacon.phtml" after="-" />
|
128 |
+
</reference>
|
129 |
+
</checkout_onepage_success>
|
130 |
+
|
131 |
+
</layout>
|
app/design/frontend/enterprise/default/template/bazaarvoice/display/headerincludes.phtml
ADDED
@@ -0,0 +1,4 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php if(Mage::getStoreConfig("bazaarvoice/general/enable_bv") === "1"): ?>
|
2 |
+
<?php $bvApiUrl = Mage::helper('bazaarvoice')->getBvApiHostUrl(true); ?>
|
3 |
+
<script type="text/javascript" src="<?php echo $bvApiUrl ?>/bvapi.js"></script>
|
4 |
+
<?php endif; ?>
|
app/design/frontend/enterprise/default/template/bazaarvoice/display/headerproduct.phtml
ADDED
@@ -0,0 +1,30 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php if(Mage::getStoreConfig("bazaarvoice/general/enable_bv") === "1"): ?>
|
2 |
+
|
3 |
+
<?php
|
4 |
+
$product = Mage::registry('product');
|
5 |
+
$productId = '';
|
6 |
+
if(strlen($product->getId())) {
|
7 |
+
$productId = Mage::helper('bazaarvoice')->getProductId($product);
|
8 |
+
}
|
9 |
+
?>
|
10 |
+
|
11 |
+
<?php if(strlen($product->getId())): ?>
|
12 |
+
<script type="text/javascript">
|
13 |
+
$BV.configure('global', { productId : "<?php echo $productId ?>" });
|
14 |
+
</script>
|
15 |
+
|
16 |
+
<?php else: ?>
|
17 |
+
|
18 |
+
<script type="text/javascript" language="javascript">
|
19 |
+
<?php // Comment out extra features until we know we need them ?>
|
20 |
+
<?php //var profileDisplayContainerPageName = "bazaarvoice/profile/display"; ?>
|
21 |
+
var configData = {};
|
22 |
+
<?php if (false) { //!empty($submissionContainerUrl)) {
|
23 |
+
echo " configData.submissionContainerUrl = \"".$submissionContainerUrl."\";\n";
|
24 |
+
} ?>
|
25 |
+
$BV.configure("global", configData);
|
26 |
+
</script>
|
27 |
+
|
28 |
+
<?php endif; ?>
|
29 |
+
|
30 |
+
<?php endif; ?>
|
app/design/frontend/enterprise/default/template/bazaarvoice/display/qa/questions.phtml
ADDED
@@ -0,0 +1,15 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php if(Mage::getStoreConfig("bazaarvoice/general/enable_bv") === "1"): ?>
|
2 |
+
<?php
|
3 |
+
$doShowContentJs = Mage::getStoreConfig('bazaarvoice/qa/do_show_content_js');
|
4 |
+
?>
|
5 |
+
<?php if(Mage::getStoreConfig("bazaarvoice/qa/enable_qa") === "1"): ?>
|
6 |
+
<div id="BVQAContainer"></div>
|
7 |
+
<script type="text/javascript">
|
8 |
+
$BV.ui( 'qa', 'show_questions', {
|
9 |
+
doShowContent : function () {
|
10 |
+
<?php echo $doShowContentJs ?>
|
11 |
+
}
|
12 |
+
});
|
13 |
+
</script>
|
14 |
+
<?php endif; ?>
|
15 |
+
<?php endif; ?>
|
app/design/frontend/enterprise/default/template/bazaarvoice/display/qa/questionsummary.phtml
ADDED
@@ -0,0 +1,5 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php if(Mage::getStoreConfig("bazaarvoice/general/enable_bv") === "1"): ?>
|
2 |
+
<?php if(Mage::getStoreConfig("bazaarvoice/qa/enable_qa") === "1"): ?>
|
3 |
+
<div id="BVQASummaryContainer"></div>
|
4 |
+
<?php endif; ?>
|
5 |
+
<?php endif; ?>
|
app/design/frontend/enterprise/default/template/bazaarvoice/display/rr/ratings.phtml
ADDED
@@ -0,0 +1,15 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php if ($this->getIsEnabled()):?>
|
2 |
+
<script type="text/javascript">
|
3 |
+
$BV.ui( 'rr', 'inline_ratings', {
|
4 |
+
productIds : {
|
5 |
+
<?php foreach($this->getLoadedProductCollection() as $_product): ?>
|
6 |
+
<?php $_productId = Mage::helper('bazaarvoice')->getProductId($_product); ?>
|
7 |
+
'<?php echo $_productId ?>' : {
|
8 |
+
url : '<?php echo $_product->getProductUrl() ?>'
|
9 |
+
},
|
10 |
+
<?php endforeach; ?>
|
11 |
+
},
|
12 |
+
containerPrefix : 'BVRRInlineRating'
|
13 |
+
});
|
14 |
+
</script>
|
15 |
+
<?php endif; ?>
|
app/design/frontend/enterprise/default/template/bazaarvoice/display/rr/reviews.phtml
ADDED
@@ -0,0 +1,16 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php if ($this->getIsEnabled()):?>
|
2 |
+
<?php
|
3 |
+
$doShowContentJs = Mage::getStoreConfig('bazaarvoice/rr/do_show_content_js');
|
4 |
+
$seoContent = $this->getSEOContent();
|
5 |
+
?>
|
6 |
+
<div id="BVRRContainer">
|
7 |
+
<?php echo $seoContent ?>
|
8 |
+
</div>
|
9 |
+
<script type="text/javascript">
|
10 |
+
$BV.ui( 'rr', 'show_reviews', {
|
11 |
+
doShowContent : function () {
|
12 |
+
<?php echo $doShowContentJs ?>
|
13 |
+
}
|
14 |
+
});
|
15 |
+
</script>
|
16 |
+
<?php endif; ?>
|
app/design/frontend/enterprise/default/template/bazaarvoice/display/rr/reviewsummary.phtml
ADDED
@@ -0,0 +1,5 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php if(Mage::getStoreConfig("bazaarvoice/general/enable_bv") === "1"): ?>
|
2 |
+
<?php if(Mage::getStoreConfig("bazaarvoice/rr/enable_rr") === "1"): ?>
|
3 |
+
<div id="BVRRSummaryContainer"></div>
|
4 |
+
<?php endif; ?>
|
5 |
+
<?php endif; ?>
|
app/design/frontend/enterprise/default/template/bazaarvoice/submit/roi_beacon.phtml
ADDED
@@ -0,0 +1,5 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php if ($this->getIsEnabled()):?>
|
2 |
+
<script type="text/javascript">
|
3 |
+
$BV.SI.trackTransactionPageView(<?php echo $this->getOrderDetails(); ?>);
|
4 |
+
</script>
|
5 |
+
<?php endif;?>
|
app/design/frontend/enterprise/default/template/bazaarvoice/submit/submissioncontainer.phtml
ADDED
@@ -0,0 +1,5 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php if(Mage::getStoreConfig("bazaarvoice/general/enable_bv") === "1"): ?>
|
2 |
+
<script>
|
3 |
+
$BV.container('global', {});
|
4 |
+
</script>
|
5 |
+
<?php endif;?>
|
app/etc/modules/Bazaarvoice_Connector.xml
ADDED
@@ -0,0 +1,9 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<config>
|
3 |
+
<modules>
|
4 |
+
<Bazaarvoice_Connector>
|
5 |
+
<active>true</active>
|
6 |
+
<codePool>local</codePool>
|
7 |
+
</Bazaarvoice_Connector>
|
8 |
+
</modules>
|
9 |
+
</config>
|
app/locale/en_US/template/email/bazaarvoice_notification.html
ADDED
@@ -0,0 +1,5 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
This is an automated email from the Bazaarvoice extension in your Magento installation.
|
2 |
+
|
3 |
+
---------------------------------------------------------------------------------------
|
4 |
+
{{var text}}
|
5 |
+
---------------------------------------------------------------------------------------
|
lib/Bazaarvoice/bvseosdk.php
ADDED
@@ -0,0 +1,511 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* BV PHP SEO SDK
|
5 |
+
*
|
6 |
+
* Base code to power either SEO or SEO and display. This SDK
|
7 |
+
* is provided as is and Bazaarvoice, Inc. is not responsbile
|
8 |
+
* for future mainentence or support. You are free to modify
|
9 |
+
* this SDK as needed to suit your needs.
|
10 |
+
*
|
11 |
+
* This SDK was built with the following assumptions:
|
12 |
+
* - you are running PHP 5 or greater
|
13 |
+
* - you have the curl library installed
|
14 |
+
* - every request has the user agent header
|
15 |
+
* in it (if using a CDN like Akamai additional configuration
|
16 |
+
* maybe required).
|
17 |
+
*
|
18 |
+
*/
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Example usage:
|
22 |
+
*
|
23 |
+
* require(bvsdk.php);
|
24 |
+
*
|
25 |
+
* $bv = new BV(array(
|
26 |
+
* 'deployment_zone_id' => '12325',
|
27 |
+
* 'product_id' => 'product1',
|
28 |
+
* 'cloud_key' => 'agileville-78B2EF7DE83644CAB5F8C72F2D8C8491',
|
29 |
+
* 'staging' => TRUE
|
30 |
+
* ));
|
31 |
+
*
|
32 |
+
*/
|
33 |
+
|
34 |
+
// ------------------------------------------------------------------------
|
35 |
+
|
36 |
+
/**
|
37 |
+
* BV Class
|
38 |
+
*
|
39 |
+
* When you instantiate the BV class, pass it's constructor an array
|
40 |
+
* containing the following key value pairs.
|
41 |
+
*
|
42 |
+
* Required fields:
|
43 |
+
* deployment_zone_id (string)
|
44 |
+
* product_id (string)
|
45 |
+
* cloud_key (string)
|
46 |
+
*
|
47 |
+
* Optional fields
|
48 |
+
* current_page_url (string) (defaults to detecting the current_page automtically)
|
49 |
+
* staging (boolean) (defaults to true, need to put false when go to production)
|
50 |
+
* subject_type (string) (defaults to product, for questions you can pass in categories here if needed)
|
51 |
+
* latency_timeout (int) (in millseconds) (defaults to 1000ms)
|
52 |
+
* bv_product (string) (defaults to reviews which is the only supported product right now)
|
53 |
+
* bot_list (string) (defualts to msnbot|googlebot|teoma|bingbot|yandexbot|yahoo)
|
54 |
+
*/
|
55 |
+
|
56 |
+
class BV {
|
57 |
+
|
58 |
+
/**
|
59 |
+
* BV Class Constructor
|
60 |
+
*
|
61 |
+
* The constructor takes in all the arguments via a single array.
|
62 |
+
*
|
63 |
+
* @access public
|
64 |
+
* @param array
|
65 |
+
* @return object
|
66 |
+
*/
|
67 |
+
public function __construct($params = array())
|
68 |
+
{
|
69 |
+
// check to make sure we have the required paramaters
|
70 |
+
if( empty($params) OR ! $params['deployment_zone_id'] OR ! $params['product_id'])
|
71 |
+
{
|
72 |
+
throw new Exception('BV Class missing required paramters.
|
73 |
+
BV expects an array with the following indexes: deployment_zone_id (string) and product_id
|
74 |
+
(string). ');
|
75 |
+
}
|
76 |
+
|
77 |
+
// config array, defaults are defined here
|
78 |
+
$this->config = array(
|
79 |
+
'staging' => TRUE,
|
80 |
+
'subject_type' => 'product',
|
81 |
+
'latency_timeout' => 1000,
|
82 |
+
'current_page_url' => $this->_getCurrentUrl(),
|
83 |
+
'bot_detection' => TRUE, // for some clients who are behind a CDN or something they may want to include SEO content with every request
|
84 |
+
'include_display_integration_code' => FALSE,
|
85 |
+
'client_name' => $params['deployment_zone_id'],
|
86 |
+
'internal_file_path' => FALSE,
|
87 |
+
'bot_list' => 'msnbot|google|teoma|bingbot|yandexbot|yahoo', // used in regex to determine if request is a bot or not
|
88 |
+
);
|
89 |
+
|
90 |
+
// merge passed in params with defualts for config.
|
91 |
+
$this->config = array_merge($this->config, $params);
|
92 |
+
|
93 |
+
// setup the reviews object
|
94 |
+
$this->reviews = new Reviews($this->config);
|
95 |
+
|
96 |
+
// setup the questions object
|
97 |
+
$this->questions = new Questions($this->config);
|
98 |
+
|
99 |
+
}
|
100 |
+
|
101 |
+
// since this is used to set the default for an optional config option it is
|
102 |
+
// included in the BV class.
|
103 |
+
public function _getCurrentUrl(){
|
104 |
+
// depending on protocal set the
|
105 |
+
// beginging of url and defualt port
|
106 |
+
if(isset($_SERVER["HTTPS"])){
|
107 |
+
$url = 'https://';
|
108 |
+
$defaultPort = '443';
|
109 |
+
}else{
|
110 |
+
$url = 'http://';
|
111 |
+
$defaultPort = '80';
|
112 |
+
}
|
113 |
+
|
114 |
+
$url .= $_SERVER["SERVER_NAME"];
|
115 |
+
|
116 |
+
// if there is a port other than the defaultPort being used it needs to be included
|
117 |
+
if ($_SERVER["SERVER_PORT"] != $defaultPort){
|
118 |
+
$url .= ":".$_SERVER["SERVER_PORT"];
|
119 |
+
}
|
120 |
+
|
121 |
+
$url .= $_SERVER["REQUEST_URI"];
|
122 |
+
|
123 |
+
return $url;
|
124 |
+
}
|
125 |
+
} // end of BV class
|
126 |
+
|
127 |
+
// Most shared functionatly is here so when we add support for questions
|
128 |
+
// and answers it should be minimal changes. Just need to create an answers
|
129 |
+
// class which inherits from Base.
|
130 |
+
class Base{
|
131 |
+
|
132 |
+
public function __construct($params = array())
|
133 |
+
{
|
134 |
+
if ( ! $params)
|
135 |
+
{
|
136 |
+
throw new Exception('BV Base Class missing config array.');
|
137 |
+
}
|
138 |
+
|
139 |
+
$this->config = $params;
|
140 |
+
|
141 |
+
// setup bv (internal) defaults
|
142 |
+
$this->bv_config['seo-domain']['staging'] = 'seo-stg.bazaarvoice.com';
|
143 |
+
$this->bv_config['seo-domain']['production'] = 'seo.bazaarvoice.com';
|
144 |
+
}
|
145 |
+
|
146 |
+
/**
|
147 |
+
* Render SEO
|
148 |
+
*
|
149 |
+
* Method used to do all the work to fetch, parse, and then return
|
150 |
+
* the SEO payload. This is set as protected so classes inheriting
|
151 |
+
* from the base class can invoke it or replace it if needed.
|
152 |
+
*
|
153 |
+
* @access protected
|
154 |
+
* @return string
|
155 |
+
*/
|
156 |
+
protected function _renderSEO()
|
157 |
+
{
|
158 |
+
// we will return a payload of a string
|
159 |
+
$pay_load = '';
|
160 |
+
|
161 |
+
// we only want to render SEO when it's a search engine bot
|
162 |
+
if ($this->_isBot())
|
163 |
+
{
|
164 |
+
|
165 |
+
// get the page number of SEO content to load
|
166 |
+
$page_number = $this->_getPageNumber();
|
167 |
+
|
168 |
+
// build the URL to access the SEO content for
|
169 |
+
// this product / page combination
|
170 |
+
$seo_url = $this->_buildSeoUrl($page_number);
|
171 |
+
|
172 |
+
// make call to get SEO payload from cloud
|
173 |
+
$seo_content = $this->_fetchSeoContent($seo_url);
|
174 |
+
|
175 |
+
// replace tokens for pagination URLs with page_url
|
176 |
+
$seo_content = $this->_replaceTokens($seo_content);
|
177 |
+
|
178 |
+
// if debug mode is on we want to include more debug data
|
179 |
+
if (isset($_GET['bvreveal']))
|
180 |
+
{
|
181 |
+
if($_GET['bvreveal'] == 'debug')
|
182 |
+
{
|
183 |
+
$printable_config = $this->config;
|
184 |
+
unset($printable_config['cloud_key']);
|
185 |
+
$seo_content .= $this->_buildComment('Config options: '.print_r($printable_config, TRUE));
|
186 |
+
}
|
187 |
+
}
|
188 |
+
|
189 |
+
$pay_load = $seo_content;
|
190 |
+
}
|
191 |
+
else
|
192 |
+
{
|
193 |
+
$pay_load = $this->_buildComment('Bot not detected, JavaScript-only');
|
194 |
+
}
|
195 |
+
|
196 |
+
return $pay_load;
|
197 |
+
}
|
198 |
+
|
199 |
+
|
200 |
+
// --------------------------------------------------------------------
|
201 |
+
/* Private methods. Internal workings of SDK. */
|
202 |
+
//--------------------------------------------------------------------
|
203 |
+
|
204 |
+
/**
|
205 |
+
* isBot
|
206 |
+
*
|
207 |
+
* Helper method to determine if current request is a bot or not. Will
|
208 |
+
* use the configured regex string which can be overriden with params.
|
209 |
+
*
|
210 |
+
* @access private
|
211 |
+
* @return bool
|
212 |
+
*/
|
213 |
+
private function _isBot()
|
214 |
+
{
|
215 |
+
// we need to check the user agent string to see if this is a bot,
|
216 |
+
// unless the bvreveal parameter is there or we have disabled bot
|
217 |
+
// detection through the bot_detection flag
|
218 |
+
if(isset($_GET['bvreveal']) OR ! $this->config['bot_detection']){
|
219 |
+
return TRUE;
|
220 |
+
}
|
221 |
+
|
222 |
+
// search the user agent string for an indictation if this is a search bot or not
|
223 |
+
return preg_match('/('.$this->config['bot_list'].')/i', $_SERVER['HTTP_USER_AGENT']);
|
224 |
+
}
|
225 |
+
|
226 |
+
/**
|
227 |
+
* getPageNumber
|
228 |
+
*
|
229 |
+
* Helper method to pull from the URL the page of SEO we need to view.
|
230 |
+
*
|
231 |
+
* @access private
|
232 |
+
* @return int
|
233 |
+
*/
|
234 |
+
private function _getPageNumber()
|
235 |
+
{
|
236 |
+
// default to page 1 if a page is not specified in the URL
|
237 |
+
$page_number = 1;
|
238 |
+
|
239 |
+
// some implementations wil use bvpage query parameter like ?bvpage=2
|
240 |
+
if (isset($_GET['bvpage'])){
|
241 |
+
$page_number = (int) $_GET['bvpage'];
|
242 |
+
|
243 |
+
// remove the bvpage parameter from the current URL so we don't keep appending it
|
244 |
+
$seo_param = str_replace('/', '\/', $_GET['bvrrp']); // need to escape slashses for regex
|
245 |
+
$this->config['current_page_url'] = preg_replace('/[?&]bvrrp='.$seo_param.'/', '', $this->config['current_page_url']);
|
246 |
+
}
|
247 |
+
// other implementations use the bvrrp, bvqap, or bvsyp parameter ?bvrrp=1234-en_us/reviews/product/2/ASF234.htm
|
248 |
+
else if(isset($_GET['bvrrp']) OR isset($_GET['bvqap']) OR isset($_GET['bvsyp']) ){
|
249 |
+
if(isset($_GET['bvrrp']))
|
250 |
+
{
|
251 |
+
$bvparam = $_GET['bvrrp'];
|
252 |
+
}
|
253 |
+
else if(isset($_GET['bvqap']))
|
254 |
+
{
|
255 |
+
$bvparam = $_GET['bvqap'];
|
256 |
+
}
|
257 |
+
else
|
258 |
+
{
|
259 |
+
$bvparam = $_GET['bvsyp'];
|
260 |
+
}
|
261 |
+
|
262 |
+
preg_match('/\/(\d+?)\/[^\/]+$/', $_SERVER['QUERY_STRING'], $page_number);
|
263 |
+
$page_number = max(1, (int) $page_number[1]);
|
264 |
+
|
265 |
+
// remove the bvrrp parameter from the current URL so we don't keep appending it
|
266 |
+
$seo_param = str_replace('/', '\/', $bvparam); // need to escape slashses for regex
|
267 |
+
$this->config['current_page_url'] = preg_replace('/[?&]bvrrp='.$seo_param.'/', '', $this->config['current_page_url']);
|
268 |
+
}
|
269 |
+
|
270 |
+
return $page_number;
|
271 |
+
}// end of _getPageNumber()
|
272 |
+
|
273 |
+
/**
|
274 |
+
* buildSeoUrl
|
275 |
+
*
|
276 |
+
* Helper method to that builds the URL to the SEO payload
|
277 |
+
*
|
278 |
+
* @access private
|
279 |
+
* @param int (page number)
|
280 |
+
* @return string
|
281 |
+
*/
|
282 |
+
private function _buildSeoUrl($page_number){
|
283 |
+
// are we pointing at staging or production?
|
284 |
+
if($this->config['staging']){
|
285 |
+
$hostname = $this->bv_config['seo-domain']['staging'];
|
286 |
+
}else{
|
287 |
+
$hostname = $this->bv_config['seo-domain']['production'];
|
288 |
+
}
|
289 |
+
|
290 |
+
// dictates order of URL
|
291 |
+
$url_parts = array(
|
292 |
+
'http://'.$hostname,
|
293 |
+
$this->config['cloud_key'],
|
294 |
+
$this->config['deployment_zone_id'],
|
295 |
+
$this->config['bv_product'],
|
296 |
+
$this->config['subject_type'],
|
297 |
+
$page_number,
|
298 |
+
urlencode($this->config['product_id']).'.htm'
|
299 |
+
);
|
300 |
+
|
301 |
+
// if our SEO content source is a file path
|
302 |
+
// we need to remove the first two sections
|
303 |
+
// and prepend the passed in file path
|
304 |
+
if($this->config['internal_file_path'])
|
305 |
+
{
|
306 |
+
unset($url_parts[0]);
|
307 |
+
unset($url_parts[1]);
|
308 |
+
|
309 |
+
return $this->config['internal_file_path'].implode("/", $url_parts);
|
310 |
+
}
|
311 |
+
|
312 |
+
// implode will convert array to a string with / in between each value in array
|
313 |
+
return implode("/", $url_parts);
|
314 |
+
}
|
315 |
+
|
316 |
+
private function _fetchSeoContent($resource)
|
317 |
+
{
|
318 |
+
if($this->config['internal_file_path'])
|
319 |
+
{
|
320 |
+
return $this->_fetchFileContent($resource);
|
321 |
+
}
|
322 |
+
else
|
323 |
+
{
|
324 |
+
return $this->_fetchCloudContent($resource);
|
325 |
+
}
|
326 |
+
}
|
327 |
+
|
328 |
+
/**
|
329 |
+
* fetchFileContent
|
330 |
+
*
|
331 |
+
* Helper method that will take in a file path and return it's payload while
|
332 |
+
* handling the possible errors or exceptions that can happen.
|
333 |
+
*
|
334 |
+
* @access private
|
335 |
+
* @param string (valid file path)
|
336 |
+
* @return string (contents of file)
|
337 |
+
*/
|
338 |
+
private function _fetchFileContent($path){
|
339 |
+
return file_get_contents($path);
|
340 |
+
}
|
341 |
+
|
342 |
+
|
343 |
+
/**
|
344 |
+
* fetchCloudContent
|
345 |
+
*
|
346 |
+
* Helper method that will take in a URL and return it's payload while
|
347 |
+
* handling the possible errors or exceptions that can happen.
|
348 |
+
*
|
349 |
+
* @access private
|
350 |
+
* @param string (valid url)
|
351 |
+
* @return string
|
352 |
+
*/
|
353 |
+
private function _fetchCloudContent($url){
|
354 |
+
|
355 |
+
// is cURL installed yet?
|
356 |
+
// if ( ! function_exists('curl_init')){
|
357 |
+
// return '<!-- curl library is not installed -->';
|
358 |
+
// }
|
359 |
+
|
360 |
+
// create a new cURL resource handle
|
361 |
+
$ch = curl_init();
|
362 |
+
|
363 |
+
curl_setopt($ch, CURLOPT_URL, $url); // Set URL to download
|
364 |
+
curl_setopt($ch, CURLOPT_REFERER, $this->config['current_page_url']); // Set a referer as coming from the current page url
|
365 |
+
curl_setopt($ch, CURLOPT_HEADER, 0); // Include header in result? (0 = yes, 1 = no)
|
366 |
+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // Should cURL return or print out the data? (true = return, false = print)
|
367 |
+
curl_setopt($ch, CURLOPT_TIMEOUT, ($this->config['latency_timeout'] / 1000)); // Timeout in seconds
|
368 |
+
|
369 |
+
// make the request to the given URL and then store the response, request info, and error number
|
370 |
+
// so we can use them later
|
371 |
+
$request = array(
|
372 |
+
'response' => curl_exec($ch),
|
373 |
+
'info' => curl_getinfo($ch),
|
374 |
+
'error_number' => curl_errno($ch),
|
375 |
+
'error_message' => curl_error($ch)
|
376 |
+
);
|
377 |
+
|
378 |
+
// Close the cURL resource, and free system resources
|
379 |
+
curl_close($ch);
|
380 |
+
|
381 |
+
// see if we got any errors with the connection
|
382 |
+
if($request['error_number'] != 0){
|
383 |
+
$msg = 'Error - '.$request['error_message'];
|
384 |
+
$this->_buildComment($msg);
|
385 |
+
}
|
386 |
+
|
387 |
+
// see if we got a status code of something other than 200
|
388 |
+
if($request['info']['http_code'] != 200){
|
389 |
+
$msg = 'HTTP status code of '.$request['info']['http_code'].' was returned';
|
390 |
+
return $this->_buildComment($msg);
|
391 |
+
}
|
392 |
+
|
393 |
+
// if we are here we got a response so let's return it
|
394 |
+
$msg = 'timer '.($request['info']['total_time'] * 1000).'ms';
|
395 |
+
return $request['response'].$this->_buildComment($msg);
|
396 |
+
}
|
397 |
+
|
398 |
+
/**
|
399 |
+
* replaceTokens
|
400 |
+
*
|
401 |
+
* After we have an SEO payload we need to replace the {INSERT_PAGE_URI}
|
402 |
+
* tokens with the current page url so pagination works.
|
403 |
+
*
|
404 |
+
* @access private
|
405 |
+
* @param string (valid url)
|
406 |
+
* @return string
|
407 |
+
*/
|
408 |
+
|
409 |
+
private function _replaceTokens($content){
|
410 |
+
// determine if query string exists in current page url
|
411 |
+
if (parse_url($this->config['current_page_url'], PHP_URL_QUERY) != ''){
|
412 |
+
// append an amperstand, because the URL already has a ? mark
|
413 |
+
$page_url_query_prefix = '&';
|
414 |
+
} else {
|
415 |
+
// append a question mark, since this URL currently has no query
|
416 |
+
$page_url_query_prefix = '?';
|
417 |
+
}
|
418 |
+
|
419 |
+
$content = str_replace('{INSERT_PAGE_URI}', $this->config['current_page_url'] . $page_url_query_prefix, $content);
|
420 |
+
|
421 |
+
return $content;
|
422 |
+
}
|
423 |
+
|
424 |
+
private function _buildComment($msg){
|
425 |
+
return "\n".'<!--BVSEO|dp: '.$this->config['deployment_zone_id'].'|sdk: v1.0-p|msg: '.$msg.' -->';
|
426 |
+
}
|
427 |
+
|
428 |
+
} // end of Base class
|
429 |
+
|
430 |
+
|
431 |
+
class Reviews extends Base{
|
432 |
+
|
433 |
+
function __construct($params = array())
|
434 |
+
{
|
435 |
+
// call Base Class constructor
|
436 |
+
parent::__construct($params);
|
437 |
+
|
438 |
+
// since we are in the reviews class
|
439 |
+
// we need to set the bv_product config
|
440 |
+
// to reviews so we get reviews in our
|
441 |
+
// SEO request
|
442 |
+
$this->config['bv_product'] = 'reviews';
|
443 |
+
|
444 |
+
// for reviews subject type will always
|
445 |
+
// need to be product
|
446 |
+
$this->config['subject_type'] = 'product';
|
447 |
+
}
|
448 |
+
|
449 |
+
public function renderSeo()
|
450 |
+
{
|
451 |
+
$pay_load = $this->_renderSeo();
|
452 |
+
|
453 |
+
// if they want to power display integration as well
|
454 |
+
// then we need to include the JS integration code
|
455 |
+
// regardless of if it's a bot or not
|
456 |
+
if($this->config['include_display_integration_code'])
|
457 |
+
{
|
458 |
+
$pay_load .= '
|
459 |
+
<script>
|
460 |
+
$BV.ui("rr", "show_reviews", {
|
461 |
+
productId: "'.$this->config['product_id'].'"
|
462 |
+
});
|
463 |
+
</script>
|
464 |
+
';
|
465 |
+
}
|
466 |
+
|
467 |
+
return $pay_load;
|
468 |
+
|
469 |
+
}
|
470 |
+
} // end of Reviews class
|
471 |
+
|
472 |
+
|
473 |
+
class Questions extends Base{
|
474 |
+
|
475 |
+
function __construct($params = array())
|
476 |
+
{
|
477 |
+
// call Base Class constructor
|
478 |
+
parent::__construct($params);
|
479 |
+
|
480 |
+
// since we are in the questions class
|
481 |
+
// we need to set the bv_product config
|
482 |
+
// to questions so we get questions in our
|
483 |
+
// SEO request
|
484 |
+
$this->config['bv_product'] = 'questions';
|
485 |
+
}
|
486 |
+
|
487 |
+
public function renderSeo()
|
488 |
+
{
|
489 |
+
$pay_load = $this->_renderSeo();
|
490 |
+
|
491 |
+
// if they want to power display integration as well
|
492 |
+
// then we need to include the JS integration code
|
493 |
+
// regardless of if it's a bot or not
|
494 |
+
if($this->config['include_display_integration_code'])
|
495 |
+
{
|
496 |
+
|
497 |
+
$pay_load .= '
|
498 |
+
<script>
|
499 |
+
$BV.ui("qa", "show_questions", {
|
500 |
+
productId: "'.$this->config['product_id'].'"
|
501 |
+
});
|
502 |
+
</script>
|
503 |
+
';
|
504 |
+
}
|
505 |
+
|
506 |
+
return $pay_load;
|
507 |
+
|
508 |
+
}
|
509 |
+
} // end of Questions class
|
510 |
+
|
511 |
+
// end of bvsdk.php
|
package.xml
ADDED
@@ -0,0 +1,18 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<package>
|
3 |
+
<name>Bazaarvoice_Connector</name>
|
4 |
+
<version>6.0.3</version>
|
5 |
+
<stability>stable</stability>
|
6 |
+
<license>Bazaarvoice, Inc.</license>
|
7 |
+
<channel>community</channel>
|
8 |
+
<extends/>
|
9 |
+
<summary>Integration extension for Bazaarvoice customers</summary>
|
10 |
+
<description>See www.bazaarvoice.com for further details on our offerings</description>
|
11 |
+
<notes>Plugin corresponds to version 6.0.2 of the Bazaarvoice platform</notes>
|
12 |
+
<authors><author><name>BV DTS</name><user>bvdts</user><email>dts@bazaarvoice.com</email></author></authors>
|
13 |
+
<date>2014-03-22</date>
|
14 |
+
<time>12:55:01</time>
|
15 |
+
<contents><target name="magelocal"><dir name="Bazaarvoice"><dir name="Connector"><dir name="Block"><file name="Bazaarvoice.php" hash="473e92e58fd86c823fb55765ed473414"/><file name="Ratings.php" hash="6822db584f2ee777beb8d39c662e8465"/><file name="Reviews.php" hash="b10079b4b57e8738f7a0f3e4a119b44a"/><dir name="Roi"><file name="Beacon.php" hash="060af59693b1471a98e6b065bad6d93d"/></dir><file name="Submissioncontainer.php" hash="23d04ee9ece011d107bb8b914653a24d"/></dir><dir name="Helper"><file name="Data.php" hash="e088fc56bc227516c34e8614ac572ba2"/></dir><dir name="Model"><file name="ExportProductFeed.php" hash="c118c7b0b6a9c2e2dee9554db2b54b8e"/><file name="ExportPurchaseFeed.php" hash="8d9400ea078aa22e162b9265542ec1bf"/><dir name="Mysql4"><file name="Setup.php" hash="884c886c1e9fa395f05e7872ba6478a2"/></dir><dir name="ProductFeed"><file name="Brand.php" hash="b2ab72e79d7e3afe23b38bc3b64ba115"/><file name="Category.php" hash="c08fe52655879ca6d47caed30c657d7d"/><file name="Product.php" hash="31c7c3c0617326642eb6157613572702"/></dir><file name="RetrieveInlineRatingsFeed.php" hash="d9b5548838a43917de916dbd5266b48a"/><file name="RetrieveSmartSEOPackage.php" hash="eab3badfb13d16965d280ca13109abe6"/><dir name="Source"><file name="AuthenticationMethod.php" hash="582d6c76372bac64728e6e4d68f959e4"/><file name="Environment.php" hash="1e575c9adb480df80e4a8a917960bd55"/><file name="FeedGenerationScope.php" hash="b2450e4c0c69b0da328f1d0d7d67012a"/><file name="TriggeringEvent.php" hash="fa47f3a2fcec92d9603f21541c853035"/></dir></dir><dir name="controllers"><file name="FeedController.php" hash="933a1555d97ac2cec8ea52306cf63102"/><file name="IndexController.php" hash="16b9a353153d40ebc32e759112ca6d6f"/></dir><dir name="etc"><file name="adminhtml.xml" hash="39cf8642bfc219709849618519a1c767"/><file name="config.xml" hash="add14265cecfb9e3e0698db626e23df0"/><file name="system.xml" hash="4ab043c44acad63a53bd9f47d3825fae"/></dir><dir name="sql"><dir name="bazaarvoice_setup"><file name="mysql4-install-0.1.0.php" hash="d721fefe4be8cee31e6bd25b8252dca6"/></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Bazaarvoice_Connector.xml" hash="c517b52d29fec93a83a8010451368ee1"/></dir></target><target name="magedesign"><dir name="frontend"><dir name="enterprise"><dir name="default"><dir name="template"><dir name="bazaarvoice"><dir name="display"><file name="headerincludes.phtml" hash="0faf96303bfe38e1c4130dfdbaff9c87"/><file name="headerproduct.phtml" hash="0d468a860f9d5ad8ae03c77e04c6089c"/><dir name="qa"><file name="questions.phtml" hash="ba5dbc762b3d43e31e492f2937bb3f3b"/><file name="questionsummary.phtml" hash="c6044994c1d355730d7e5cfd3a6e3125"/></dir><dir name="rr"><file name="ratings.phtml" hash="56047515b347d0250d44e4e2eb0a923c"/><file name="reviews.phtml" hash="7d2ad8b18910010d22240c9521131290"/><file name="reviewsummary.phtml" hash="75e823088dd75387fc94e6028d8236a5"/></dir></dir><dir name="submit"><file name="roi_beacon.phtml" hash="494b9a44ceb14b1f376611d30ac18645"/><file name="submissioncontainer.phtml" hash="3f3f22b922c1aa5b87f7bbf4fbeea51c"/></dir></dir></dir><dir name="layout"><file name="bazaarvoice.xml" hash="aaf26cfadf47936077b764356b0e1ab2"/></dir></dir></dir></dir></target><target name="magelocale"><dir name="en_US"><dir name="template"><dir name="email"><file name="bazaarvoice_notification.html" hash="9a0e90ac62d926dad4db13719f3c8b73"/></dir></dir></dir></target><target name="mageskin"><dir name="frontend"><dir name="base"><dir name="default"><dir name="images"><dir name="bazaarvoice"><file name="rating-0_0.gif" hash="f50bd3f45f69a753614b2e76f53bdafc"/><file name="rating-1_0.gif" hash="c691e11e3250a18939aec523734d9b67"/><file name="rating-1_1.gif" hash="26377f1337bb6fb9e340292243a6f780"/><file name="rating-1_2.gif" hash="5c51583dc52d901c61d9470d5faeb2a4"/><file name="rating-1_3.gif" hash="3948c716d18ea0389ce9e57c347e7b6d"/><file name="rating-1_4.gif" hash="2211d8586bda467cb8fcc617670b94df"/><file name="rating-1_5.gif" hash="3fa9480c8b86f85749147fa0e8144b05"/><file name="rating-1_6.gif" hash="a577c79e7ea0c6c59ac15251c39de515"/><file name="rating-1_7.gif" hash="b5b52fa267632eda6ba5b3be56319397"/><file name="rating-1_8.gif" hash="205170e1ffbfcc81569286a9e1a88eb5"/><file name="rating-1_9.gif" hash="63709f7b2a2e2f14ae442dbef6513f25"/><file name="rating-2_0.gif" hash="4eec2468b5e41dc03d198ed6fe084a53"/><file name="rating-2_1.gif" hash="155cab7b16f4cfef3e94b99ca297cedc"/><file name="rating-2_2.gif" hash="2e2dc606fd83853bdf90a3beb901cf3e"/><file name="rating-2_3.gif" hash="638632f37a750558722c0bf1a79f2546"/><file name="rating-2_4.gif" hash="6b0a85c21066c6402b9f8914284b999f"/><file name="rating-2_5.gif" hash="c4792dac3b9d5a914a72a4200f931c6e"/><file name="rating-2_6.gif" hash="1c7ac3f4e3721d4779721973cfaaa8db"/><file name="rating-2_7.gif" hash="21b680dce6ffef505532afea7fea1452"/><file name="rating-2_8.gif" hash="136ac6b284d1a2b9452a06eea993c1fa"/><file name="rating-2_9.gif" hash="d13af6920569aa85da6dfb0a139d560a"/><file name="rating-3_0.gif" hash="6b30e597cc23aec52dbd2be978d52351"/><file name="rating-3_1.gif" hash="cb544d168a949100fb5ee117adbd765b"/><file name="rating-3_2.gif" hash="75124c4b4dfc5cbcf5ae3ccfa7bdf906"/><file name="rating-3_3.gif" hash="0693b6a471361957da1dc8ee2e9af5ec"/><file name="rating-3_4.gif" hash="1a6e3cff41a61e1bbed9296badb94392"/><file name="rating-3_5.gif" hash="7f63ecf505414386267fad2e92617a9f"/><file name="rating-3_6.gif" hash="8b9b9ccebc3537cffd2bed75c60eaa9e"/><file name="rating-3_7.gif" hash="7f83f3996a738d1fd6763204cd964376"/><file name="rating-3_8.gif" hash="219a1f2dbd45bcb58a58f460c9491bbf"/><file name="rating-3_9.gif" hash="e4114607ca469db2fd5f87ac21c4f00a"/><file name="rating-4_0.gif" hash="a15541525186bf6911202e0f64daa4a6"/><file name="rating-4_1.gif" hash="818971c067beb397247095f5eedbac29"/><file name="rating-4_2.gif" hash="5b9599176771adfbf8c52c7dfa04e565"/><file name="rating-4_3.gif" hash="18dc68db736819e17ab5cf0d5725d99c"/><file name="rating-4_4.gif" hash="56b124f1a2e599918b462ce29cd1cd96"/><file name="rating-4_5.gif" hash="2044f11b1f7005f66f14219c5fce1020"/><file name="rating-4_6.gif" hash="3166f044e7f73f9b3e75bda4507eaa35"/><file name="rating-4_7.gif" hash="20546d3ebee7a364927e9da9274996a7"/><file name="rating-4_8.gif" hash="9dab0f19785d1592a96c5c295842f308"/><file name="rating-4_9.gif" hash="19a47143b04aceae85def246059fba33"/><file name="rating-5_0.gif" hash="e43b403663785255d2f023ca35566ac3"/></dir></dir></dir></dir></dir></target><target name="magelib"><dir name="Bazaarvoice"><file name="bvseosdk.php" hash="01c63530a4b80a7a70555b5005a4ba5c"/></dir></target><target name="mageweb"><dir name="shell"><file name="bv_export_order_feed.php" hash="309995ede2f85d95a0b91d8845c06ae5"/><file name="bv_export_product_feed.php" hash="1696c363c97bf9943560045b297c98fb"/></dir></target></contents>
|
16 |
+
<compatible/>
|
17 |
+
<dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
|
18 |
+
</package>
|
shell/bv_export_order_feed.php
ADDED
@@ -0,0 +1,38 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
*
|
4 |
+
*/
|
5 |
+
|
6 |
+
require 'app/Mage.php';
|
7 |
+
|
8 |
+
if (!Mage::isInstalled()) {
|
9 |
+
echo "Application is not installed yet, please complete install wizard first.";
|
10 |
+
exit;
|
11 |
+
}
|
12 |
+
|
13 |
+
// Only for urls
|
14 |
+
// Don't remove this
|
15 |
+
$_SERVER['SCRIPT_NAME'] = str_replace(basename(__FILE__), 'index.php', $_SERVER['SCRIPT_NAME']);
|
16 |
+
$_SERVER['SCRIPT_FILENAME'] = str_replace(basename(__FILE__), 'index.php', $_SERVER['SCRIPT_FILENAME']);
|
17 |
+
|
18 |
+
Mage::app('admin')->setUseSessionInUrl(false);
|
19 |
+
|
20 |
+
umask(0);
|
21 |
+
|
22 |
+
try {
|
23 |
+
// Log mem usage
|
24 |
+
echo "\n" . 'Memory usage: ' . memory_get_usage() . "\n";
|
25 |
+
|
26 |
+
// Create model
|
27 |
+
$exportModel = Mage::getModel('bazaarvoice/exportPurchaseFeed');
|
28 |
+
|
29 |
+
// Call export
|
30 |
+
$exportModel->exportPurchaseFeed();
|
31 |
+
|
32 |
+
// Log mem usage
|
33 |
+
echo 'Memory usage: ' . memory_get_usage() . "\n";
|
34 |
+
|
35 |
+
} catch (Exception $e) {
|
36 |
+
Mage::printException($e);
|
37 |
+
}
|
38 |
+
|
shell/bv_export_product_feed.php
ADDED
@@ -0,0 +1,38 @@
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
|
Â
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
*
|
4 |
+
*/
|
5 |
+
|
6 |
+
require 'app/Mage.php';
|
7 |
+
|
8 |
+
if (!Mage::isInstalled()) {
|
9 |
+
echo "Application is not installed yet, please complete install wizard first.";
|
10 |
+
exit;
|
11 |
+
}
|
12 |
+
|
13 |
+
// Only for urls
|
14 |
+
// Don't remove this
|
15 |
+
$_SERVER['SCRIPT_NAME'] = str_replace(basename(__FILE__), 'index.php', $_SERVER['SCRIPT_NAME']);
|
16 |
+
$_SERVER['SCRIPT_FILENAME'] = str_replace(basename(__FILE__), 'index.php', $_SERVER['SCRIPT_FILENAME']);
|
17 |
+
|
18 |
+
Mage::app('admin')->setUseSessionInUrl(false);
|
19 |
+
|
20 |
+
umask(0);
|
21 |
+
|
22 |
+
try {
|
23 |
+
// Log mem usage
|
24 |
+
echo "\n" . 'Memory usage: ' . memory_get_usage() . "\n";
|
25 |
+
|
26 |
+
// Create model
|
27 |
+
$exportModel = Mage::getModel('bazaarvoice/exportProductFeed');
|
28 |
+
|
29 |
+
// Call export
|
30 |
+
$exportModel->exportDailyProductFeed();
|
31 |
+
|
32 |
+
// Log mem usage
|
33 |
+
echo 'Memory usage: ' . memory_get_usage() . "\n";
|
34 |
+
|
35 |
+
} catch (Exception $e) {
|
36 |
+
Mage::printException($e);
|
37 |
+
}
|
38 |
+
|
skin/frontend/base/default/images/bazaarvoice/rating-0_0.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-1_0.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-1_1.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-1_2.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-1_3.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-1_4.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-1_5.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-1_6.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-1_7.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-1_8.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-1_9.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-2_0.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-2_1.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-2_2.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-2_3.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-2_4.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-2_5.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-2_6.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-2_7.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-2_8.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-2_9.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-3_0.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-3_1.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-3_2.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-3_3.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-3_4.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-3_5.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-3_6.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-3_7.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-3_8.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-3_9.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-4_0.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-4_1.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-4_2.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-4_3.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-4_4.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-4_5.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-4_6.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-4_7.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-4_8.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-4_9.gif
ADDED
Binary file
|
skin/frontend/base/default/images/bazaarvoice/rating-5_0.gif
ADDED
Binary file
|