neklo_instagram - Version 1.1.0

Version Notes

New instagram api support added

Download this release

Release Info

Developer NEKLO
Extension neklo_instagram
Version 1.1.0
Comparing to
See all releases


Code changes from version 1.0.3 to 1.1.0

Files changed (61) hide show
  1. app/code/community/Neklo/Core/Block/System/Abstract.php +0 -62
  2. app/code/community/Neklo/Core/Block/System/Contact.php +7 -156
  3. app/code/community/Neklo/Core/Block/System/Contact/Header.php +17 -0
  4. app/code/community/Neklo/Core/Block/System/Contact/Send.php +20 -0
  5. app/code/community/Neklo/Core/Block/System/Contact/Send/Button.php +35 -0
  6. app/code/community/Neklo/Core/Block/System/Extension.php +16 -0
  7. app/code/community/Neklo/Core/Block/System/Extension/List.php +104 -0
  8. app/code/community/Neklo/Core/Block/System/Extensions.php +0 -66
  9. app/code/community/Neklo/Core/Block/System/Newsletter.php +0 -9
  10. app/code/community/Neklo/Core/Block/System/Newsletter/Subscribe.php +19 -19
  11. app/code/community/Neklo/Core/Block/System/Newsletter/Subscribe/Button.php +34 -34
  12. app/code/community/Neklo/Core/Helper/Config.php +16 -0
  13. app/code/community/Neklo/Core/Helper/Data.php +9 -1
  14. app/code/community/Neklo/Core/Helper/Extension.php +104 -0
  15. app/code/community/Neklo/Core/Model/Feed.php +91 -33
  16. app/code/community/Neklo/Core/Model/Feed/Extension.php +48 -0
  17. app/code/community/Neklo/Core/Model/Observer.php +41 -5
  18. app/code/community/Neklo/Core/Model/Source/Reason.php +28 -0
  19. app/code/community/Neklo/Core/Model/Source/Subscription/Type.php +45 -0
  20. app/code/community/Neklo/Core/Model/System/Config/Backend/Empty.php +9 -0
  21. app/code/community/Neklo/Core/controllers/Adminhtml/Neklo/Core/ContactController.php +10 -13
  22. app/code/community/Neklo/Core/controllers/Adminhtml/Neklo/Core/NewsletterController.php +46 -46
  23. app/code/community/Neklo/Core/etc/config.xml +20 -12
  24. app/code/community/Neklo/Core/etc/system.xml +98 -11
  25. app/code/community/Neklo/Instagram/Block/Adminhtml/System/Config/Frontend/Oauth.php +33 -0
  26. app/code/community/Neklo/Instagram/Block/Adminhtml/System/Config/Frontend/Oauth/Connect.php +73 -0
  27. app/code/community/Neklo/Instagram/Block/Adminhtml/System/Config/Frontend/Oauth/Disconnect.php +41 -0
  28. app/code/community/Neklo/Instagram/Block/Adminhtml/System/Config/Frontend/Status.php +36 -0
  29. app/code/community/Neklo/Instagram/Block/Widget/Feed.php +125 -46
  30. app/code/community/Neklo/Instagram/Helper/Config.php +59 -0
  31. app/code/community/Neklo/Instagram/Helper/Data.php +27 -15
  32. app/code/community/Neklo/Instagram/Model/Instagram.php +122 -103
  33. app/code/community/Neklo/Instagram/Model/Instagram/Api.php +839 -567
  34. app/code/community/Neklo/Instagram/Model/Source/Mode.php +60 -0
  35. app/code/community/Neklo/Instagram/Model/System/Config/Backend/Empty.php +9 -0
  36. app/code/community/Neklo/Instagram/controllers/Adminhtml/Neklo/Instagram/ApiController.php +84 -0
  37. app/code/community/Neklo/Instagram/etc/adminhtml.xml +22 -22
  38. app/code/community/Neklo/Instagram/etc/config.xml +82 -61
  39. app/code/community/Neklo/Instagram/etc/system.xml +85 -35
  40. app/code/community/Neklo/Instagram/etc/widget.xml +121 -109
  41. app/code/community/Neklo/Instagram/sql/neklo_instagram_setup/mysql4-install-1.0.0.php +32 -34
  42. app/design/adminhtml/default/default/layout/neklo/core.xml +10 -0
  43. app/design/adminhtml/default/default/layout/neklo/instagram.xml +10 -0
  44. app/design/adminhtml/default/default/template/neklo/core/system/contact/button.phtml +190 -0
  45. app/design/adminhtml/default/default/template/neklo/core/system/contact/header.phtml +2 -0
  46. app/design/adminhtml/default/default/template/neklo/core/system/extension/list.phtml +25 -0
  47. app/design/adminhtml/default/default/template/neklo/core/system/subscribe/button.phtml +180 -161
  48. app/design/adminhtml/default/default/template/neklo/instagram/reload.phtml +4 -0
  49. app/design/adminhtml/default/default/template/neklo/instagram/system/config/oauth/connect.phtml +20 -0
  50. app/design/adminhtml/default/default/template/neklo/instagram/system/config/oauth/disconnect.phtml +11 -0
  51. app/design/frontend/base/default/template/neklo_instagram/widget/feed.phtml +19 -23
  52. app/etc/modules/Neklo_Instagram.xml +12 -12
  53. app/locale/en_US/Neklo_Instagram.csv +18 -17
  54. package.xml +1 -17
  55. skin/adminhtml/default/default/neklo/core/css/style.css +52 -0
  56. skin/adminhtml/default/default/neklo/core/images/ok.gif +0 -0
  57. skin/adminhtml/default/default/neklo/core/images/update.gif +0 -0
  58. skin/adminhtml/default/default/neklo/instagram/css/styles.css +10 -0
  59. skin/frontend/base/default/neklo/instagram/css/style.css +110 -110
  60. skin/frontend/base/default/neklo/instagram/sass/mixin/_mixin.scss +156 -156
  61. skin/frontend/base/default/neklo/instagram/sass/style.scss +77 -77
app/code/community/Neklo/Core/Block/System/Abstract.php DELETED
@@ -1,62 +0,0 @@
1
- <?php
2
-
3
- class Neklo_Core_Block_System_Abstract extends Mage_Adminhtml_Block_System_Config_Form_Fieldset
4
- {
5
- protected $_modules;
6
- protected $_fieldRenderer;
7
-
8
- protected function _getFieldRenderer()
9
- {
10
- if (empty($this->_fieldRenderer)) {
11
- $this->_fieldRenderer = Mage::getBlockSingleton('adminhtml/system_config_form_field');
12
- }
13
- return $this->_fieldRenderer;
14
- }
15
-
16
- protected function _getFooterHtml($element)
17
- {
18
- $html = parent::_getFooterHtml($element);
19
- $html .= Mage::helper('adminhtml/js')->getScript(
20
- "
21
- $$('td.form-buttons')[0].update('');
22
- $('{$element->getHtmlId()}' + '-head').setStyle('background: none;');
23
- $('{$element->getHtmlId()}' + '-head').writeAttribute('onclick', 'return false;');
24
- $('{$element->getHtmlId()}').show();
25
- "
26
- );
27
- return $html;
28
- }
29
-
30
- protected function _getModules()
31
- {
32
- if (is_null($this->modules)) {
33
- $array = (array)Mage::getConfig()->getNode('modules')->children();
34
- ksort($array);
35
- $modules = array();
36
- $cache = array();
37
- foreach ($array as $code => $item) {
38
- $name = explode('_', $code, 2);
39
-
40
- if (!$item->is('active', 'true')
41
- || !isset($name)
42
- || $name[0] != 'Neklo'
43
- || $code == 'Neklo_Core'
44
- ) {
45
- continue;
46
- }
47
-
48
- $modules[] = $code;
49
- $config = Mage::getConfig()->getNode('modules/' . $code);
50
- $version = explode('.', $config->version);
51
- $version = (intval($version[0]) - 1) << 12 | intval($version[1]) << 6 | intval($version[2]) << 0;
52
- $cache[] = dechex(intval($config->build)) . 't' . dechex(intval($config->build) - hexdec($config->encoding)) . 't' . substr(md5(strtolower($code)), 0, 2) . $version;
53
- }
54
- $cache = implode('n', $cache);
55
- $param = '<domain></domain>' . 'cache/' . $cache;
56
- $param = str_replace('<domain>' . '</domain>', '/', $param) . '/';
57
- $this->getRequest()->setPost('neklo_' . 'cache', $param);
58
- $this->modules = $modules;
59
- }
60
- return $this->modules;
61
- }
62
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/Neklo/Core/Block/System/Contact.php CHANGED
@@ -1,165 +1,16 @@
1
  <?php
2
 
3
- class Neklo_Core_Block_System_Contact extends Neklo_Core_Block_System_Abstract
4
  {
5
- public function render(Varien_Data_Form_Element_Abstract $element)
6
  {
7
- $fields = array(
8
- array(
9
- 'type' => 'text',
10
- 'name' => 'name',
11
- 'label' => $this->__('Contact Name'),
12
- 'class' => 'required-entry',
13
- ),
14
- array(
15
- 'type' => 'text',
16
- 'name' => 'email',
17
- 'label' => $this->__('Contact Email'),
18
- 'class' => 'required-entry validate-email',
19
- ),
20
- array(
21
- 'type' => 'text',
22
- 'name' => 'subject',
23
- 'label' => $this->__('Subject'),
24
- 'class' => 'required-entry'),
25
- array(
26
- 'type' => 'select',
27
- 'name' => 'reason',
28
- 'label' => $this->__('Reason'),
29
- 'values' => $this->_getReasons(),
30
- 'class' => 'required-entry',
31
- 'onchange' => 'NekloContact.toggleReason()',
32
- ),
33
- array(
34
- 'type' => 'text',
35
- 'name' => 'other_reason',
36
- 'label' => $this->__('Other Reason'),
37
- 'class' => 'required-entry',
38
- 'onchange' => 'NekloContact.toggleReason()',
39
- ),
40
- array(
41
- 'type' => 'textarea',
42
- 'name' => 'message',
43
- 'label' => $this->__('Message'),
44
- 'class' => 'required-entry',
45
- ),
46
- array(
47
- 'type' => 'label',
48
- 'name' => 'send',
49
- 'after_element_html' => '<div class="right"><button type="button" class="scalable save" onclick="NekloContact.submit()">' . $this->__('Send') . '</button></div><div class="notice" id="ajax-response"></div>',
50
- ),
51
- );
52
- if (!$element->getForm()) {
53
- return '';
54
- }
55
- $html = $this->_getHeaderHtml($element);
56
- foreach ($fields as $field) {
57
- $html .= $this->_getFieldHtml($element, $field);
58
- }
59
- $html .= $this->_getFooterHtml($element);
60
- return $html;
61
  }
62
 
63
- protected function _getReasons()
64
  {
65
- $modules = $this->_getModules();
66
-
67
- $reasons[] = array(
68
- 'label' => $this->__('Please select'),
69
- 'value' => ''
70
- );
71
- $reasons[] = array(
72
- 'label' => $this->__('Magento Related Support (paid)'),
73
- 'value' => 'Magento v' . Mage::getVersion()
74
- );
75
- $reasons[] = array(
76
- 'label' => $this->__('Request New Extension Development (paid)'),
77
- 'value' => 'New Extension'
78
- );
79
- foreach ($modules as $code) {
80
- $moduleConfig = Mage::getConfig()->getNode('modules/' . $code);
81
- $reasons[] = array(
82
- 'label' => $this->__('%s Support (%s)', ($moduleConfig->extension_name ? $moduleConfig->extension_name : $code) . ' v' . $moduleConfig->version, ($moduleConfig->free ? $this->__('paid') : $this->__('free'))),
83
- 'value' => $code . ' ' . $moduleConfig->version,
84
- );
85
- }
86
- $reasons[] = array(
87
- 'label' => $this->__('Other Reason'),
88
- 'value' => 'other',
89
- );
90
- return $reasons;
91
- }
92
-
93
- protected function _getFooterHtml($element)
94
- {
95
- $ajaxUrl = $this->getUrl('adminhtml/neklo_core_contact');
96
- $html = parent::_getFooterHtml($element);
97
- $html = '<h4>' . $this->__('Contact Neklo Support Team or visit <a href="%s" target="_blank">%s</a> for additional information', 'http://store.neklo.com/', 'store.neklo.com') . '</h4>' . $html;
98
-
99
- $html .= Mage::helper('adminhtml/js')->getScript(
100
- '
101
- var NekloContact = {
102
- toggleReason: function() {
103
- if ($("reason").getValue() != "other"){
104
- $("other_reason").up(1).hide();
105
- $("other_reason").disable();
106
- } else {
107
- $("other_reason").enable();
108
- $("other_reason").up(1).show();
109
- }
110
- },
111
- submit: function() {
112
- if (supportForm.validator.validate()){
113
- new Ajax.Request(
114
- "' . $ajaxUrl . '",
115
- {
116
- method: "post",
117
- parameters: Form.serialize($("' . $element->getHtmlId() . '")),
118
- onSuccess:function(transport){
119
- if (transport && transport.responseText){
120
- try {
121
- response = eval("(" + transport.responseText + ")");
122
- } catch (e) {
123
- response = {};
124
- }
125
- }
126
-
127
- if ((typeof response.message) == "string") {
128
- $("ajax-response").update(response.message);
129
- } else {
130
- $("ajax-response").update(response.message.join("<br/>"));
131
- }
132
-
133
- if (response.error==0) {
134
- $("subject").value = "";
135
- $("other_reason").value = "";
136
- $("message").value = "";
137
- $("reason").selectedIndex = 0;
138
- }
139
-
140
- new PeriodicalExecuter(function(pe){ $("ajax-response").update(""); pe.stop(); }, 20);
141
- }
142
- }
143
- );
144
- }
145
- }
146
- };
147
-
148
- NekloContact.toggleReason();
149
- supportForm = new varienForm($(' . $element->getHtmlId() . '));
150
- '
151
- );
152
- return $html;
153
- }
154
-
155
- protected function _getFieldHtml($fieldset, $field)
156
- {
157
- $type = $field['type'];
158
- unset($field['type']);
159
- $field = $fieldset
160
- ->addField($field['name'], $type, $field)
161
- ->setRenderer($this->_getFieldRenderer())
162
- ;
163
- return $field->toHtml();
164
  }
165
  }
1
  <?php
2
 
3
+ class Neklo_Core_Block_System_Contact extends Mage_Adminhtml_Block_System_Config_Form_Fieldset
4
  {
5
+ protected function _getHeaderHtml($element)
6
  {
7
+ return parent::_getHeaderHtml($element) . $this->_getAfterHeaderHtml();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  }
9
 
10
+ protected function _getAfterHeaderHtml()
11
  {
12
+ $subscribeButton = $this->getLayout()->createBlock('neklo_core/system_contact_header', 'neklo_core_contact_header');
13
+ $subscribeButton->setTemplate('neklo/core/system/contact/header.phtml');
14
+ return $subscribeButton->toHtml();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  }
16
  }
app/code/community/Neklo/Core/Block/System/Contact/Header.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Neklo_Core_Block_System_Contact_Header extends Mage_Adminhtml_Block_Template
4
+ {
5
+ const STORE_URL = 'http://store.neklo.com/';
6
+ const STORE_LABEL = 'store.neklo.com';
7
+
8
+ public function getStoreUrl()
9
+ {
10
+ return self::STORE_URL;
11
+ }
12
+
13
+ public function getStoreLabel()
14
+ {
15
+ return self::STORE_LABEL;
16
+ }
17
+ }
app/code/community/Neklo/Core/Block/System/Contact/Send.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Neklo_Core_Block_System_Contact_Send extends Mage_Adminhtml_Block_System_Config_Form_Field
4
+ {
5
+ public function render(Varien_Data_Form_Element_Abstract $element)
6
+ {
7
+ $element->setScope(false);
8
+ $element->setCanUseWebsiteValue(false);
9
+ $element->setCanUseDefaultValue(false);
10
+ return parent::render($element);
11
+ }
12
+
13
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
14
+ {
15
+ $subscribeButton = $this->getLayout()->createBlock('neklo_core/system_contact_send_button', 'neklo_core_contact_send');
16
+ $subscribeButton->setTemplate('neklo/core/system/contact/button.phtml');
17
+ $subscribeButton->setContainerId($element->getContainer()->getHtmlId());
18
+ return $subscribeButton->toHtml();
19
+ }
20
+ }
app/code/community/Neklo/Core/Block/System/Contact/Send/Button.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Neklo_Core_Block_System_Contact_Send_Button extends Mage_Adminhtml_Block_Template
4
+ {
5
+ /**
6
+ * @return Mage_Adminhtml_Block_Widget_Button
7
+ */
8
+ public function getButton()
9
+ {
10
+ $button = $this->getLayout()->createBlock('adminhtml/widget_button');
11
+ $button
12
+ ->setType('button')
13
+ ->setLabel($this->__('Send'))
14
+ ->setStyle("width:280px")
15
+ ->setId('neklo_core_contact_send')
16
+ ;
17
+ return $button;
18
+ }
19
+
20
+ /**
21
+ * @return string
22
+ */
23
+ public function getButtonHtml()
24
+ {
25
+ return $this->getButton()->toHtml();
26
+ }
27
+
28
+ /**
29
+ * @return string
30
+ */
31
+ public function getContainerId()
32
+ {
33
+ return parent::getContainerId();
34
+ }
35
+ }
app/code/community/Neklo/Core/Block/System/Extension.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Neklo_Core_Block_System_Extension extends Mage_Adminhtml_Block_System_Config_Form_Fieldset
4
+ {
5
+ protected function _getHeaderHtml($element)
6
+ {
7
+ return parent::_getHeaderHtml($element) . $this->_getContentHtml();
8
+ }
9
+
10
+ protected function _getContentHtml()
11
+ {
12
+ $extensionListBlock = $this->getLayout()->createBlock('neklo_core/system_extension_list', 'neklo_core_extension_list');
13
+ $extensionListBlock->setTemplate('neklo/core/system/extension/list.phtml');
14
+ return $extensionListBlock->toHtml();
15
+ }
16
+ }
app/code/community/Neklo/Core/Block/System/Extension/List.php ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Neklo_Core_Block_System_Extension_List extends Mage_Adminhtml_Block_Template
4
+ {
5
+ const DOMAIN = 'http://store.neklo.com/';
6
+ const IMAGE_EXTENSION = '.jpg';
7
+
8
+ protected $_feedData = null;
9
+
10
+ /**
11
+ * @param string $code
12
+ *
13
+ * @return bool
14
+ */
15
+ public function canShowExtension($code)
16
+ {
17
+ $feedData = $this->_getExtensionInfo(strtolower($code));
18
+ return !!count($feedData);
19
+ }
20
+
21
+ /**
22
+ * @return array
23
+ */
24
+ public function getExtensionList()
25
+ {
26
+ return Mage::helper('neklo_core/extension')->getModuleConfigList();
27
+ }
28
+
29
+ /**
30
+ * @param string $code
31
+ *
32
+ * @return mixed
33
+ */
34
+ public function getExtensionName($code)
35
+ {
36
+ $feedData = $this->_getExtensionInfo(strtolower($code));
37
+ if (!array_key_exists('name', $feedData)) {
38
+ return $code;
39
+ }
40
+ return $feedData['name'];
41
+ }
42
+
43
+ /**
44
+ * @param string $code
45
+ * @param $config
46
+ *
47
+ * @return bool
48
+ */
49
+ public function isExtensionVersionOutdated($code, $config)
50
+ {
51
+ $currentVersion = $this->getExtensionVersion($config);
52
+ $lastVersion = $this->getLastExtensionVersion($code);
53
+ return version_compare($currentVersion, $lastVersion) === -1;
54
+ }
55
+
56
+ public function getExtensionVersion($config)
57
+ {
58
+ $version = (string)$config->version;
59
+ if (!$version) {
60
+ return '';
61
+ }
62
+ return $version;
63
+ }
64
+
65
+ public function getLastExtensionVersion($code)
66
+ {
67
+ $feedData = $this->_getExtensionInfo(strtolower($code));
68
+ if (!array_key_exists('version', $feedData)) {
69
+ return '0';
70
+ }
71
+ return $feedData['version'];
72
+ }
73
+
74
+ public function getExtensionUrl($code)
75
+ {
76
+ $feedData = $this->_getExtensionInfo(strtolower($code));
77
+ if (!array_key_exists('url', $feedData)) {
78
+ return null;
79
+ }
80
+ return $feedData['url'];
81
+ }
82
+
83
+ public function getImageUrl($code)
84
+ {
85
+ $imgUrl = self::DOMAIN . 'cache/' . ($this->_getCacheKey() ? $this->_getCacheKey() . '/' : '') . strtolower($code) . self::IMAGE_EXTENSION;
86
+ return $imgUrl;
87
+ }
88
+
89
+ protected function _getCacheKey()
90
+ {
91
+ return Mage::helper('neklo_core/extension')->getCacheKey();
92
+ }
93
+
94
+ protected function _getExtensionInfo($code)
95
+ {
96
+ if (is_null($this->_feedData)) {
97
+ $this->_feedData = Mage::getModel('neklo_core/feed_extension')->getFeed();
98
+ }
99
+ if (!array_key_exists($code, $this->_feedData)) {
100
+ return array();
101
+ }
102
+ return $this->_feedData[$code];
103
+ }
104
+ }
app/code/community/Neklo/Core/Block/System/Extensions.php DELETED
@@ -1,66 +0,0 @@
1
- <?php
2
-
3
- class Neklo_Core_Block_System_Extensions extends Neklo_Core_Block_System_Abstract
4
- {
5
- public function render(Varien_Data_Form_Element_Abstract $element)
6
- {
7
- $html = $this->_getHeaderHtml($element);
8
- $html .= '<tr><td colspan="2"><h4>' . $this->__('Installed Neklo Extensions') . '</h4></td></tr>';
9
- $html .= $this->_getContentHtml($element);
10
- $html .= $this->_getFooterHtml($element);
11
- $html .= '<style>.installed-extensions td {padding: 4px;}</style>';
12
- return $html;
13
- }
14
-
15
- protected function _getContentHtml($fieldset)
16
- {
17
- $html = '<tr class="installed-extensions">';
18
- $modules = $this->_getModules();
19
- $count = count($modules);
20
-
21
- $columns = 0;
22
- if ($count < 6) {
23
- $columns = 5;
24
- } elseif ($count % 5 == 0) {
25
- $columns = 5;
26
- } elseif ($count % 4 == 0) {
27
- $columns = 4;
28
- } elseif ($count % 3 == 0) {
29
- $columns = 3;
30
- } elseif (($count + 1) % 5 == 0) {
31
- $columns = 5;
32
- } elseif (($count + 1) % 4 == 0) {
33
- $columns = 4;
34
- } elseif (($count + 1) % 3 == 0) {
35
- $columns = 3;
36
- } else {
37
- $columns = 4;
38
- }
39
-
40
- foreach ($modules as $index => $code) {
41
- if (($index % $columns) == 0 && $index != 0) {
42
- $html .= '</tr><tr class="installed-extensions">';
43
- }
44
- $html .= '<td align="center">';
45
-
46
- $config = Mage::getConfig()->getNode('modules/' . $code);
47
-
48
- $name = ($config->extension_name ? $config->extension_name : $code);
49
-
50
- $imgUrl = Mage::app()->getRequest()->getParam('neklo_cache') . strtolower($code) . '.jpg';
51
- $img = '<img src="' . $imgUrl . '" alt="' . $name . '">';
52
-
53
- if ($config->url) {
54
- $url = '<domain></domain>' . $config->url . '.html';
55
- $url = str_replace('<domain>' . '</domain>', '/', $url);
56
- $img = '<a href="' . $url . '" target="_blank">' . $img . '</a>';
57
- }
58
-
59
- $html .= $img . '<br>';
60
- $html .= $name . '<br>v' . $config->version;
61
- $html .= '</td>';
62
- }
63
- $html .= '</tr>';
64
- return $html;
65
- }
66
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/Neklo/Core/Block/System/Newsletter.php DELETED
@@ -1,9 +0,0 @@
1
- <?php
2
-
3
- class Neklo_Core_Block_System_Newsletter extends Mage_Adminhtml_Block_System_Config_Form_Fieldset
4
- {
5
- protected function _getHeaderTitleHtml($element)
6
- {
7
- return '<div class="entry-edit-head collapseable"><a id="' . $element->getHtmlId() . '-head" href="#" style="background:none;">' . $element->getLegend() . '</a></div>';
8
- }
9
- }
 
 
 
 
 
 
 
 
 
app/code/community/Neklo/Core/Block/System/Newsletter/Subscribe.php CHANGED
@@ -1,20 +1,20 @@
1
- <?php
2
-
3
- class Neklo_Core_Block_System_Newsletter_Subscribe extends Mage_Adminhtml_Block_System_Config_Form_Field
4
- {
5
- public function render(Varien_Data_Form_Element_Abstract $element)
6
- {
7
- $element->setScope(false);
8
- $element->setCanUseWebsiteValue(false);
9
- $element->setCanUseDefaultValue(false);
10
- return parent::render($element);
11
- }
12
-
13
- protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
14
- {
15
- $subscribeButton = $this->getLayout()->createBlock('neklo_core/system_newsletter_subscribe_button', 'neklo_core_subscribe');
16
- $subscribeButton->setTemplate('neklo/core/system/subscribe/button.phtml');
17
- $subscribeButton->setContainerId($element->getContainer()->getHtmlId());
18
- return $subscribeButton->toHtml();
19
- }
20
  }
1
+ <?php
2
+
3
+ class Neklo_Core_Block_System_Newsletter_Subscribe extends Mage_Adminhtml_Block_System_Config_Form_Field
4
+ {
5
+ public function render(Varien_Data_Form_Element_Abstract $element)
6
+ {
7
+ $element->setScope(false);
8
+ $element->setCanUseWebsiteValue(false);
9
+ $element->setCanUseDefaultValue(false);
10
+ return parent::render($element);
11
+ }
12
+
13
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
14
+ {
15
+ $subscribeButton = $this->getLayout()->createBlock('neklo_core/system_newsletter_subscribe_button', 'neklo_core_subscribe');
16
+ $subscribeButton->setTemplate('neklo/core/system/subscribe/button.phtml');
17
+ $subscribeButton->setContainerId($element->getContainer()->getHtmlId());
18
+ return $subscribeButton->toHtml();
19
+ }
20
  }
app/code/community/Neklo/Core/Block/System/Newsletter/Subscribe/Button.php CHANGED
@@ -1,35 +1,35 @@
1
- <?php
2
-
3
- class Neklo_Core_Block_System_Newsletter_Subscribe_Button extends Mage_Adminhtml_Block_Template
4
- {
5
- /**
6
- * @return Mage_Adminhtml_Block_Widget_Button
7
- */
8
- public function getButton()
9
- {
10
- $button = $this->getLayout()->createBlock('adminhtml/widget_button');
11
- $button
12
- ->setType('button')
13
- ->setLabel($this->__('Subscribe'))
14
- ->setStyle("width:280px")
15
- ->setId('neklo_core_subscribe')
16
- ;
17
- return $button;
18
- }
19
-
20
- /**
21
- * @return string
22
- */
23
- public function getButtonHtml()
24
- {
25
- return $this->getButton()->toHtml();
26
- }
27
-
28
- /**
29
- * @return string
30
- */
31
- public function getContainerId()
32
- {
33
- return parent::getContainerId();
34
- }
35
  }
1
+ <?php
2
+
3
+ class Neklo_Core_Block_System_Newsletter_Subscribe_Button extends Mage_Adminhtml_Block_Template
4
+ {
5
+ /**
6
+ * @return Mage_Adminhtml_Block_Widget_Button
7
+ */
8
+ public function getButton()
9
+ {
10
+ $button = $this->getLayout()->createBlock('adminhtml/widget_button');
11
+ $button
12
+ ->setType('button')
13
+ ->setLabel($this->__('Subscribe'))
14
+ ->setStyle("width:280px")
15
+ ->setId('neklo_core_subscribe')
16
+ ;
17
+ return $button;
18
+ }
19
+
20
+ /**
21
+ * @return string
22
+ */
23
+ public function getButtonHtml()
24
+ {
25
+ return $this->getButton()->toHtml();
26
+ }
27
+
28
+ /**
29
+ * @return string
30
+ */
31
+ public function getContainerId()
32
+ {
33
+ return parent::getContainerId();
34
+ }
35
  }
app/code/community/Neklo/Core/Helper/Config.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Neklo_Core_Helper_Config extends Mage_Compiler_Helper_Data
4
+ {
5
+ const NOTIFICATION_TYPE = 'neklo_core/notification/type';
6
+
7
+ /**
8
+ * @param null|int|Mage_Core_Model_Store $store
9
+ *
10
+ * @return array
11
+ */
12
+ public function getNotificationTypeList($store = null)
13
+ {
14
+ return explode(',', Mage::getStoreConfig(self::NOTIFICATION_TYPE, $store));
15
+ }
16
+ }
app/code/community/Neklo/Core/Helper/Data.php CHANGED
@@ -2,6 +2,9 @@
2
 
3
  class Neklo_Core_Helper_Data extends Mage_Core_Helper_Abstract
4
  {
 
 
 
5
  public function __()
6
  {
7
  $args = func_get_args();
@@ -15,6 +18,11 @@ class Neklo_Core_Helper_Data extends Mage_Core_Helper_Abstract
15
 
16
  protected function _getLogoUrl()
17
  {
18
- return $this->_getRequest()->getPost('neklo_cache') . 'neklo.png';
 
 
 
 
 
19
  }
20
  }
2
 
3
  class Neklo_Core_Helper_Data extends Mage_Core_Helper_Abstract
4
  {
5
+ const DOMAIN = 'http://store.neklo.com/';
6
+ const LOGO_IMG = 'neklo.png';
7
+
8
  public function __()
9
  {
10
  $args = func_get_args();
18
 
19
  protected function _getLogoUrl()
20
  {
21
+ return self::DOMAIN . 'cache/' . ($this->_getCacheKey() ? $this->_getCacheKey() . '/' : '') . self::LOGO_IMG;
22
+ }
23
+
24
+ protected function _getCacheKey()
25
+ {
26
+ return Mage::helper('neklo_core/extension')->getCacheKey();
27
  }
28
  }
app/code/community/Neklo/Core/Helper/Extension.php ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Neklo_Core_Helper_Extension extends Mage_Core_Helper_Abstract
4
+ {
5
+ protected $_protectedModuleCodeList = array(
6
+ 'Neklo_Core'
7
+ );
8
+
9
+ protected $_cacheKey = null;
10
+ protected $_moduleConfigList = null;
11
+ protected $_moduleList = null;
12
+
13
+ public function getModuleList()
14
+ {
15
+ if (is_null($this->_moduleList)) {
16
+ $moduleList = array();
17
+ foreach ($this->getModuleConfigList() as $moduleCode => $moduleConfig) {
18
+ $moduleList[$moduleCode] = array(
19
+ 'name' => $moduleConfig->extension_name ? $moduleConfig->extension_name : $moduleCode,
20
+ 'version' => $moduleConfig->version,
21
+ );
22
+ }
23
+ $this->_moduleList = $moduleList;
24
+ }
25
+ return $this->_moduleList;
26
+ }
27
+
28
+ public function getModuleConfigList()
29
+ {
30
+ if (is_null($this->_moduleConfigList)) {
31
+ $moduleConfigList = (array)Mage::getConfig()->getNode('modules')->children();
32
+ ksort($moduleConfigList);
33
+ $moduleList = array();
34
+ foreach ($moduleConfigList as $moduleCode => $moduleConfig) {
35
+ if (!$this->_canShowExtension($moduleCode, $moduleConfig)) {
36
+ continue;
37
+ }
38
+ $moduleList[$moduleCode] = $moduleConfig;
39
+ }
40
+ $this->_moduleConfigList = $moduleList;
41
+ }
42
+ return $this->_moduleConfigList;
43
+ }
44
+
45
+ public function getCacheKey()
46
+ {
47
+ if (is_null($this->_cacheKey)) {
48
+ $cacheList = array();
49
+ foreach ($this->getModuleConfigList() as $moduleCode => $moduleConfig) {
50
+ $version = explode('.', $moduleConfig->version);
51
+ $version = (intval($version[0]) - 1) << 12 | intval($version[1]) << 6 | intval($version[2]) << 0;
52
+ $cacheList[] = dechex(intval($moduleConfig->build)) . 't' . dechex(intval($moduleConfig->build) - hexdec($moduleConfig->encoding)) . 't' . substr(md5(strtolower($moduleCode)), 0, 2) . $version;
53
+ }
54
+ $this->_cacheKey = implode('n', $cacheList);
55
+ }
56
+ return $this->_cacheKey;
57
+ }
58
+
59
+ /**
60
+ * @param string $code
61
+ * @param Mage_Core_Model_Config_Element $config
62
+ *
63
+ * @return bool
64
+ */
65
+ protected function _canShowExtension($code, $config)
66
+ {
67
+ if (!$code || !$config) {
68
+ return false;
69
+ }
70
+ if (!($config instanceof Mage_Core_Model_Config_Element)) {
71
+ return false;
72
+ }
73
+ if (!is_object($config) || !method_exists($config, 'is') || !$config->is('active', 'true')) {
74
+ return false;
75
+ }
76
+ if (!$this->_isNekloExtension($code)) {
77
+ return false;
78
+ }
79
+ if ($this->_isProtectedExtension($code)) {
80
+ return false;
81
+ }
82
+ return true;
83
+ }
84
+
85
+ /**
86
+ * @param string $code
87
+ *
88
+ * @return bool
89
+ */
90
+ protected function _isNekloExtension($code)
91
+ {
92
+ return (strstr($code,'Neklo_') !== false);
93
+ }
94
+
95
+ /**
96
+ * @param string $code
97
+ *
98
+ * @return bool
99
+ */
100
+ protected function _isProtectedExtension($code)
101
+ {
102
+ return in_array($code, $this->_protectedModuleCodeList);
103
+ }
104
+ }
app/code/community/Neklo/Core/Model/Feed.php CHANGED
@@ -1,34 +1,92 @@
1
- <?php
2
-
3
- class Neklo_Core_Model_Feed extends Mage_AdminNotification_Model_Feed
4
- {
5
- const XML_USE_HTTPS_PATH = 'neklo_core/admin_notification/use_https';
6
- const XML_FEED_URL_PATH = 'neklo_core/admin_notification/feed_url';
7
- const XML_FREQUENCY_PATH = 'neklo_core/admin_notification/frequency';
8
-
9
- const LAST_CHECK_CACHE_KEY = 'neklo_core_admin_notifications_last_check';
10
-
11
- public function getFrequency()
12
- {
13
- return Mage::getStoreConfig(self::XML_FREQUENCY_PATH) * 3600;
14
- }
15
-
16
- public function getLastUpdate()
17
- {
18
- return Mage::app()->loadCache(self::LAST_CHECK_CACHE_KEY);
19
- }
20
-
21
- public function setLastUpdate()
22
- {
23
- Mage::app()->saveCache(time(), self::LAST_CHECK_CACHE_KEY);
24
- return $this;
25
- }
26
-
27
- public function getFeedUrl()
28
- {
29
- if (is_null($this->_feedUrl)) {
30
- $this->_feedUrl = (Mage::getStoreConfigFlag(self::XML_USE_HTTPS_PATH) ? 'https://' : 'http://') . Mage::getStoreConfig(self::XML_FEED_URL_PATH);
31
- }
32
- return $this->_feedUrl;
33
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  }
1
+ <?php
2
+
3
+ class Neklo_Core_Model_Feed extends Mage_AdminNotification_Model_Feed
4
+ {
5
+ const XML_USE_HTTPS_PATH = 'neklo_core/notification/use_https';
6
+ const XML_FEED_URL_PATH = 'neklo_core/notification/feed_url';
7
+ const XML_FREQUENCY_PATH = 'neklo_core/notification/frequency';
8
+
9
+ const LAST_CHECK_CACHE_KEY = 'neklo_core_admin_notifications_last_check';
10
+
11
+ public function getFrequency()
12
+ {
13
+ return Mage::getStoreConfig(self::XML_FREQUENCY_PATH) * 3600;
14
+ }
15
+
16
+ public function getLastUpdate()
17
+ {
18
+ return Mage::app()->loadCache(self::LAST_CHECK_CACHE_KEY);
19
+ }
20
+
21
+ public function setLastUpdate()
22
+ {
23
+ Mage::app()->saveCache(time(), self::LAST_CHECK_CACHE_KEY);
24
+ return $this;
25
+ }
26
+
27
+ public function getFeedUrl()
28
+ {
29
+ if (is_null($this->_feedUrl)) {
30
+ $this->_feedUrl = (Mage::getStoreConfigFlag(self::XML_USE_HTTPS_PATH) ? 'https://' : 'http://') . Mage::getStoreConfig(self::XML_FEED_URL_PATH);
31
+ }
32
+ return $this->_feedUrl;
33
+ }
34
+
35
+ public function checkUpdate()
36
+ {
37
+ if (($this->getFrequency() + $this->getLastUpdate()) > time()) {
38
+ return $this;
39
+ }
40
+
41
+ $feedData = array();
42
+ $feedXml = $this->getFeedData();
43
+ if ($feedXml && $feedXml->channel && $feedXml->channel->item) {
44
+ foreach ($feedXml->channel->item as $item) {
45
+ if (!$this->_isAllowedItem($item)) {
46
+ continue;
47
+ }
48
+ $feedData[] = array(
49
+ 'severity' => (int)$item->severity,
50
+ 'date_added' => $this->getDate((string)$item->pubDate),
51
+ 'title' => (string)$item->title,
52
+ 'description' => (string)$item->description,
53
+ 'url' => (string)$item->link,
54
+ );
55
+ }
56
+ if ($feedData) {
57
+ $inboxParser = Mage::getModel('adminnotification/inbox');
58
+ if ($inboxParser) {
59
+ $inboxParser->parse(array_reverse($feedData));
60
+ }
61
+ }
62
+ }
63
+ $this->setLastUpdate();
64
+ return $this;
65
+ }
66
+
67
+ protected function _isAllowedItem($item)
68
+ {
69
+ $itemType = $item->type ? $item->type : Neklo_Core_Model_Source_Subscription_Type::INFO_CODE;
70
+ $allowedTypeList = Mage::helper('neklo_core/config')->getNotificationTypeList();
71
+ if ($itemType == Neklo_Core_Model_Source_Subscription_Type::UPDATE_CODE) {
72
+ if (in_array(Neklo_Core_Model_Source_Subscription_Type::UPDATE_ALL_CODE, $allowedTypeList)) {
73
+ return true;
74
+ }
75
+ if (in_array(Neklo_Core_Model_Source_Subscription_Type::UPDATE_CODE, $allowedTypeList)) {
76
+ $installedExtensionList = array_keys(Mage::helper('neklo_core/extension')->getModuleList());
77
+ $isPresent = false;
78
+ foreach ($item->extension->children() as $extensionCode) {
79
+ if (in_array((string)$extensionCode, $installedExtensionList)) {
80
+ $isPresent = true;
81
+ }
82
+ }
83
+ return $isPresent;
84
+ }
85
+ }
86
+ if (!in_array($itemType, $allowedTypeList)) {
87
+
88
+ return false;
89
+ }
90
+ return true;
91
+ }
92
  }
app/code/community/Neklo/Core/Model/Feed/Extension.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Neklo_Core_Model_Feed_Extension
4
+ {
5
+ const FEED_URL = 'http://store.neklo.com/feed.json';
6
+ const CACHE_ID = 'NEKLO_EXTENSION_FEED';
7
+ const CACHE_LIFETIME = 172800;
8
+
9
+ public function getFeed()
10
+ {
11
+ if (!$feed = Mage::app()->loadCache(self::CACHE_ID)) {
12
+ $feed = $this->_getFeedFromResource();
13
+ $this->_save($feed);
14
+ }
15
+ $feedArray = Mage::helper('core')->jsonDecode($feed);
16
+ if (!is_array($feedArray)) {
17
+ $feedArray = array();
18
+ }
19
+ return $feedArray;
20
+ }
21
+
22
+ protected function _getFeedFromResource()
23
+ {
24
+ $ch = curl_init();
25
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
26
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
27
+ curl_setopt($ch, CURLOPT_URL, self::FEED_URL);
28
+ curl_setopt(
29
+ $ch,
30
+ CURLOPT_HTTPHEADER,
31
+ array(
32
+ 'Content-Type: application/json'
33
+ )
34
+ );
35
+ $result = curl_exec($ch);
36
+ if (curl_getinfo($ch, CURLINFO_HTTP_CODE) != 200) {
37
+ $result = '{}';
38
+ }
39
+ curl_close($ch);
40
+ return $result;
41
+ }
42
+
43
+ protected function _save($feed)
44
+ {
45
+ Mage::app()->saveCache($feed, self::CACHE_ID, array(), self::CACHE_LIFETIME);
46
+ return $this;
47
+ }
48
+ }
app/code/community/Neklo/Core/Model/Observer.php CHANGED
@@ -2,15 +2,51 @@
2
 
3
  class Neklo_Core_Model_Observer
4
  {
5
- public function renderContact($observer)
6
- {
7
- Mage::getBlockSingleton('neklo_core/system_contact')->render(new Varien_Data_Form_Element_Fieldset);
8
- }
9
-
10
  public function checkUpdate(Varien_Event_Observer $observer)
11
  {
12
  if (Mage::getSingleton('admin/session')->isLoggedIn()) {
13
  Mage::getModel('neklo_core/feed')->checkUpdate();
14
  }
15
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  }
2
 
3
  class Neklo_Core_Model_Observer
4
  {
 
 
 
 
 
5
  public function checkUpdate(Varien_Event_Observer $observer)
6
  {
7
  if (Mage::getSingleton('admin/session')->isLoggedIn()) {
8
  Mage::getModel('neklo_core/feed')->checkUpdate();
9
  }
10
  }
11
+
12
+ public function sortModuleTabList(Varien_Event_Observer $observer)
13
+ {
14
+ $configContainerBlock = $observer->getBlock();
15
+ if (!$configContainerBlock instanceof Mage_Adminhtml_Block_System_Config_Tabs) {
16
+ return null;
17
+ }
18
+ $tabList = $configContainerBlock->getTabs();
19
+ foreach ($tabList as $tab) {
20
+ if ($tab->getId() !== 'neklo') {
21
+ continue;
22
+ }
23
+
24
+ $sectionList = $tab->getSections();
25
+ if (!$sectionList || !$sectionList->getSize()) {
26
+ continue;
27
+ }
28
+
29
+ $sectionListArray = $sectionList->toArray();
30
+ $sectionListArray = $sectionListArray['items'];
31
+ usort($sectionListArray, array($this, '_sort'));
32
+
33
+ $tab->getSections()->clear();
34
+ foreach ($sectionListArray as $_section) {
35
+ $section = new Varien_Object($_section);
36
+ $section->setId($_section['id']);
37
+ $tab->getSections()->addItem($section);
38
+ }
39
+ }
40
+ }
41
+
42
+ protected function _sort($a, $b)
43
+ {
44
+ if ($a['id'] == 'neklo_core') {
45
+ return 1;
46
+ }
47
+ if ($b['id'] == 'neklo_core') {
48
+ return -1;
49
+ }
50
+ return strcasecmp($a['label'], $b['label']);
51
+ }
52
  }
app/code/community/Neklo/Core/Model/Source/Reason.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Neklo_Core_Model_Source_Reason
4
+ {
5
+ public function toOptionArray()
6
+ {
7
+ $reasonList = array();
8
+ $reasonList[''] = $this->__('Please select');
9
+ $reasonList['Magento v' . Mage::getVersion()] = $this->__('Magento Related Support');
10
+ $reasonList['New Extension'] = $this->__('Request New Extension Development');
11
+
12
+ $moduleList = Mage::helper('neklo_core/extension')->getModuleList();
13
+ foreach ($moduleList as $moduleCode => $moduleData) {
14
+ $moduleTitle = $moduleData['name'] . ' v' . $moduleData['version'];
15
+ $reasonList[$moduleCode . ' ' . $moduleData['version']] = $this->__('%s Support', $moduleTitle);
16
+ }
17
+
18
+ $reasonList['other'] = $this->__('Other Reason');
19
+ return $reasonList;
20
+ }
21
+
22
+ public function __()
23
+ {
24
+ $args = func_get_args();
25
+ $helper = Mage::helper('neklo_core');
26
+ return call_user_func_array(array($helper, "__"), $args);
27
+ }
28
+ }
app/code/community/Neklo/Core/Model/Source/Subscription/Type.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Neklo_Core_Model_Source_Subscription_Type
4
+ {
5
+ const UPDATE_CODE = 'UPDATE';
6
+ const UPDATE_LABEL = 'My extensions updates';
7
+
8
+ const RELEASE_CODE = 'RELEASE';
9
+ const RELEASE_LABEL = 'New Releases';
10
+
11
+ const UPDATE_ALL_CODE = 'UPDATE_ALL';
12
+ const UPDATE_ALL_LABEL = 'All extensions updates';
13
+
14
+ const PROMO_CODE = 'PROMO';
15
+ const PROMO_LABEL = 'Promotions / Discounts';
16
+
17
+ const INFO_CODE = 'INFO';
18
+ const INFO_LABEL = 'Other information';
19
+
20
+ public function toOptionArray()
21
+ {
22
+ return array(
23
+ array(
24
+ 'value' => self::UPDATE_CODE,
25
+ 'label' => Mage::helper('neklo_core')->__(self::UPDATE_LABEL),
26
+ ),
27
+ array(
28
+ 'value' => self::RELEASE_CODE,
29
+ 'label' => Mage::helper('neklo_core')->__(self::RELEASE_LABEL),
30
+ ),
31
+ array(
32
+ 'value' => self::UPDATE_ALL_CODE,
33
+ 'label' => Mage::helper('neklo_core')->__(self::UPDATE_ALL_LABEL),
34
+ ),
35
+ array(
36
+ 'value' => self::PROMO_CODE,
37
+ 'label' => Mage::helper('neklo_core')->__(self::PROMO_LABEL),
38
+ ),
39
+ array(
40
+ 'value' => self::INFO_CODE,
41
+ 'label' => Mage::helper('neklo_core')->__(self::INFO_LABEL),
42
+ )
43
+ );
44
+ }
45
+ }
app/code/community/Neklo/Core/Model/System/Config/Backend/Empty.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Neklo_Core_Model_System_Config_Backend_Empty extends Mage_Core_Model_Config_Data
4
+ {
5
+ public function getValue()
6
+ {
7
+ return null;
8
+ }
9
+ }
app/code/community/Neklo/Core/controllers/Adminhtml/Neklo/Core/ContactController.php CHANGED
@@ -2,12 +2,12 @@
2
 
3
  class Neklo_Core_Adminhtml_Neklo_Core_ContactController extends Mage_Adminhtml_Controller_Action
4
  {
5
- const CONTACT_URL = '<support_url></support_url>';
6
 
7
- public function indexAction()
8
  {
9
  $result = array(
10
- 'error' => 0,
11
  );
12
  try {
13
  $data = $this->getRequest()->getPost();
@@ -16,22 +16,14 @@ class Neklo_Core_Adminhtml_Neklo_Core_ContactController extends Mage_Adminhtml_C
16
  $data['id'] = '<order_item_customer></order_item_customer>';
17
  $this->_sendContactEmail($data);
18
  } catch (Exception $e) {
19
- $result['message'][] = $e->getMessage();
20
- $result['error'] = 1;
21
  $this->getResponse()->setBody(Zend_Json::encode($result));
22
  return;
23
  }
24
- $result['message'][] = $this->__("Thank you for your request.");
25
- $result['message'][] = $this->__("We'll respond as soon as possible.");
26
- $result['message'][] = $this->__("We'll send copy of your request to your email.");
27
  $this->getResponse()->setBody(Zend_Json::encode($result));
28
  }
29
 
30
- protected function _isAllowed()
31
- {
32
- return Mage::getSingleton('admin/session')->isAllowed('system/config/neklo_core');
33
- }
34
-
35
  protected function _sendContactEmail($data)
36
  {
37
  $params = Mage::helper('core')->urlEncode(Mage::helper('core')->jsonEncode($data));
@@ -51,4 +43,9 @@ class Neklo_Core_Adminhtml_Neklo_Core_ContactController extends Mage_Adminhtml_C
51
  ;
52
  }
53
  }
 
 
 
 
 
54
  }
2
 
3
  class Neklo_Core_Adminhtml_Neklo_Core_ContactController extends Mage_Adminhtml_Controller_Action
4
  {
5
+ const CONTACT_URL = 'http://store.neklo.com/neklo_support/index/index/';
6
 
7
+ public function sendAction()
8
  {
9
  $result = array(
10
+ 'success' => true,
11
  );
12
  try {
13
  $data = $this->getRequest()->getPost();
16
  $data['id'] = '<order_item_customer></order_item_customer>';
17
  $this->_sendContactEmail($data);
18
  } catch (Exception $e) {
19
+ Mage::logException($e);
20
+ $result['success'] = false;
21
  $this->getResponse()->setBody(Zend_Json::encode($result));
22
  return;
23
  }
 
 
 
24
  $this->getResponse()->setBody(Zend_Json::encode($result));
25
  }
26
 
 
 
 
 
 
27
  protected function _sendContactEmail($data)
28
  {
29
  $params = Mage::helper('core')->urlEncode(Mage::helper('core')->jsonEncode($data));
43
  ;
44
  }
45
  }
46
+
47
+ protected function _isAllowed()
48
+ {
49
+ return Mage::getSingleton('admin/session')->isAllowed('system/config/neklo_core');
50
+ }
51
  }
app/code/community/Neklo/Core/controllers/Adminhtml/Neklo/Core/NewsletterController.php CHANGED
@@ -1,47 +1,47 @@
1
- <?php
2
-
3
- class Neklo_Core_Adminhtml_Neklo_Core_NewsletterController extends Mage_Adminhtml_Controller_Action
4
- {
5
- const SUBSCRIBE_URL = '<subscribe_url></subscribe_url>';
6
-
7
- public function subscribeAction()
8
- {
9
- $result = array(
10
- 'success' => true,
11
- );
12
- try {
13
- $data = $this->getRequest()->getPost();
14
- $this->_subscribe($data);
15
- } catch (Exception $e) {
16
- $result['success'] = false;
17
- $this->getResponse()->setBody(Zend_Json::encode($result));
18
- return;
19
- }
20
- $this->getResponse()->setBody(Zend_Json::encode($result));
21
- }
22
-
23
- protected function _subscribe($data)
24
- {
25
- $params = Mage::helper('core')->urlEncode(Mage::helper('core')->jsonEncode($data));
26
- if ($params) {
27
- $httpClient = new Varien_Http_Client();
28
- $httpClient
29
- ->setMethod(Zend_Http_Client::POST)
30
- ->setUri(self::SUBSCRIBE_URL)
31
- ->setConfig(
32
- array(
33
- 'maxredirects' => 0,
34
- 'timeout' => 30,
35
- )
36
- )
37
- ->setRawData($params)
38
- ->request()
39
- ;
40
- }
41
- }
42
-
43
- protected function _isAllowed()
44
- {
45
- return Mage::getSingleton('admin/session')->isAllowed('system/config/neklo_core');
46
- }
47
  }
1
+ <?php
2
+
3
+ class Neklo_Core_Adminhtml_Neklo_Core_NewsletterController extends Mage_Adminhtml_Controller_Action
4
+ {
5
+ const SUBSCRIBE_URL = 'http://store.neklo.com/neklo_subscribe/index/index/';
6
+
7
+ public function subscribeAction()
8
+ {
9
+ $result = array(
10
+ 'success' => true,
11
+ );
12
+ try {
13
+ $data = $this->getRequest()->getPost();
14
+ $this->_subscribe($data);
15
+ } catch (Exception $e) {
16
+ $result['success'] = false;
17
+ $this->getResponse()->setBody(Zend_Json::encode($result));
18
+ return;
19
+ }
20
+ $this->getResponse()->setBody(Zend_Json::encode($result));
21
+ }
22
+
23
+ protected function _subscribe($data)
24
+ {
25
+ $params = Mage::helper('core')->urlEncode(Mage::helper('core')->jsonEncode($data));
26
+ if ($params) {
27
+ $httpClient = new Varien_Http_Client();
28
+ $httpClient
29
+ ->setMethod(Zend_Http_Client::POST)
30
+ ->setUri(self::SUBSCRIBE_URL)
31
+ ->setConfig(
32
+ array(
33
+ 'maxredirects' => 0,
34
+ 'timeout' => 30,
35
+ )
36
+ )
37
+ ->setRawData($params)
38
+ ->request()
39
+ ;
40
+ }
41
+ }
42
+
43
+ protected function _isAllowed()
44
+ {
45
+ return Mage::getSingleton('admin/session')->isAllowed('system/config/neklo_core');
46
+ }
47
  }
app/code/community/Neklo/Core/etc/config.xml CHANGED
@@ -2,7 +2,7 @@
2
  <config>
3
  <modules>
4
  <Neklo_Core>
5
- <version>1.0.2</version>
6
  </Neklo_Core>
7
  </modules>
8
  <admin>
@@ -34,6 +34,13 @@
34
  </models>
35
  </global>
36
  <adminhtml>
 
 
 
 
 
 
 
37
  <translate>
38
  <modules>
39
  <Neklo_Core>
@@ -44,14 +51,6 @@
44
  </modules>
45
  </translate>
46
  <events>
47
- <controller_action_predispatch_adminhtml_system_config_edit>
48
- <observers>
49
- <neklo_core>
50
- <class>neklo_core/observer</class>
51
- <method>renderContact</method>
52
- </neklo_core>
53
- </observers>
54
- </controller_action_predispatch_adminhtml_system_config_edit>
55
  <controller_action_predispatch>
56
  <observers>
57
  <neklo_core_admin_notification>
@@ -60,16 +59,25 @@
60
  </neklo_core_admin_notification>
61
  </observers>
62
  </controller_action_predispatch>
 
 
 
 
 
 
 
 
63
  </events>
64
  </adminhtml>
65
  <default>
66
  <neklo_core>
67
- <admin_notification>
68
- <feed_url>store.neklo.com/notifications.rss</feed_url>
69
  <use_https>0</use_https>
70
  <frequency>24</frequency>
71
  <last_update>0</last_update>
72
- </admin_notification>
 
73
  </neklo_core>
74
  </default>
75
  </config>
2
  <config>
3
  <modules>
4
  <Neklo_Core>
5
+ <version>1.1.1</version>
6
  </Neklo_Core>
7
  </modules>
8
  <admin>
34
  </models>
35
  </global>
36
  <adminhtml>
37
+ <layout>
38
+ <updates>
39
+ <awall module="Neklo_Core">
40
+ <file>neklo/core.xml</file>
41
+ </awall>
42
+ </updates>
43
+ </layout>
44
  <translate>
45
  <modules>
46
  <Neklo_Core>
51
  </modules>
52
  </translate>
53
  <events>
 
 
 
 
 
 
 
 
54
  <controller_action_predispatch>
55
  <observers>
56
  <neklo_core_admin_notification>
59
  </neklo_core_admin_notification>
60
  </observers>
61
  </controller_action_predispatch>
62
+ <adminhtml_block_html_before>
63
+ <observers>
64
+ <sort_module_tab_list>
65
+ <class>neklo_core/observer</class>
66
+ <method>sortModuleTabList</method>
67
+ </sort_module_tab_list>
68
+ </observers>
69
+ </adminhtml_block_html_before>
70
  </events>
71
  </adminhtml>
72
  <default>
73
  <neklo_core>
74
+ <notification>
75
+ <feed_url>store.neklo.com/magento-update/magento-notifications.rss</feed_url>
76
  <use_https>0</use_https>
77
  <frequency>24</frequency>
78
  <last_update>0</last_update>
79
+ <type>UPDATE,RELEASE,UPDATE_ALL,PROMO,INFO</type>
80
+ </notification>
81
  </neklo_core>
82
  </default>
83
  </config>
app/code/community/Neklo/Core/etc/system.xml CHANGED
@@ -16,29 +16,97 @@
16
  <show_in_website>1</show_in_website>
17
  <show_in_store>1</show_in_store>
18
  <groups>
19
- <extensions translate="label">
20
  <label>Extensions Information</label>
21
  <frontend_type>text</frontend_type>
22
- <frontend_model>neklo_core/system_extensions</frontend_model>
23
- <sort_order>1</sort_order>
24
  <show_in_default>1</show_in_default>
25
  <show_in_website>1</show_in_website>
26
  <show_in_store>1</show_in_store>
27
- </extensions>
 
28
  <contact translate="label">
29
  <label>Contact Form</label>
30
  <frontend_type>text</frontend_type>
31
  <frontend_model>neklo_core/system_contact</frontend_model>
32
- <sort_order>2</sort_order>
33
  <show_in_default>1</show_in_default>
34
- <show_in_website>1</show_in_website>
35
- <show_in_store>1</show_in_store>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  </contact>
37
  <newsletter translate="label">
38
  <label>Subscribe to Newsletter</label>
39
  <frontend_type>text</frontend_type>
40
- <frontend_model>neklo_core/system_newsletter</frontend_model>
41
- <sort_order>10</sort_order>
42
  <show_in_default>1</show_in_default>
43
  <show_in_website>0</show_in_website>
44
  <show_in_store>0</show_in_store>
@@ -47,20 +115,20 @@
47
  <name translate="label">
48
  <label>Name</label>
49
  <frontend_type>text</frontend_type>
 
50
  <sort_order>10</sort_order>
51
  <show_in_default>1</show_in_default>
52
  <show_in_website>0</show_in_website>
53
  <show_in_store>0</show_in_store>
54
- <validate>required-entry</validate>
55
  </name>
56
  <email translate="label">
57
  <label>Email</label>
58
  <frontend_type>text</frontend_type>
 
59
  <sort_order>20</sort_order>
60
  <show_in_default>1</show_in_default>
61
  <show_in_website>0</show_in_website>
62
  <show_in_store>0</show_in_store>
63
- <validate>required-entry validate-email</validate>
64
  </email>
65
  <subscribe_button>
66
  <frontend_model>neklo_core/system_newsletter_subscribe</frontend_model>
@@ -71,6 +139,25 @@
71
  </subscribe_button>
72
  </fields>
73
  </newsletter>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  </groups>
75
  </neklo_core>
76
  </sections>
16
  <show_in_website>1</show_in_website>
17
  <show_in_store>1</show_in_store>
18
  <groups>
19
+ <extension translate="label">
20
  <label>Extensions Information</label>
21
  <frontend_type>text</frontend_type>
22
+ <frontend_model>neklo_core/system_extension</frontend_model>
23
+ <sort_order>10</sort_order>
24
  <show_in_default>1</show_in_default>
25
  <show_in_website>1</show_in_website>
26
  <show_in_store>1</show_in_store>
27
+ <expanded>1</expanded>
28
+ </extension>
29
  <contact translate="label">
30
  <label>Contact Form</label>
31
  <frontend_type>text</frontend_type>
32
  <frontend_model>neklo_core/system_contact</frontend_model>
33
+ <sort_order>20</sort_order>
34
  <show_in_default>1</show_in_default>
35
+ <show_in_website>0</show_in_website>
36
+ <show_in_store>0</show_in_store>
37
+ <expanded>1</expanded>
38
+ <fields>
39
+ <name translate="label">
40
+ <label>Contact Name</label>
41
+ <frontend_type>text</frontend_type>
42
+ <backend_model>neklo_core/system_config_backend_empty</backend_model>
43
+ <sort_order>10</sort_order>
44
+ <show_in_default>1</show_in_default>
45
+ <show_in_website>0</show_in_website>
46
+ <show_in_store>0</show_in_store>
47
+ </name>
48
+ <email translate="label">
49
+ <label>Contact Email</label>
50
+ <frontend_type>text</frontend_type>
51
+ <backend_model>neklo_core/system_config_backend_empty</backend_model>
52
+ <sort_order>20</sort_order>
53
+ <show_in_default>1</show_in_default>
54
+ <show_in_website>0</show_in_website>
55
+ <show_in_store>0</show_in_store>
56
+ </email>
57
+ <subject translate="label">
58
+ <label>Subject</label>
59
+ <frontend_type>text</frontend_type>
60
+ <backend_model>neklo_core/system_config_backend_empty</backend_model>
61
+ <sort_order>30</sort_order>
62
+ <show_in_default>1</show_in_default>
63
+ <show_in_website>0</show_in_website>
64
+ <show_in_store>0</show_in_store>
65
+ </subject>
66
+ <reason translate="label">
67
+ <label>Reason</label>
68
+ <frontend_type>select</frontend_type>
69
+ <source_model>neklo_core/source_reason</source_model>
70
+ <backend_model>neklo_core/system_config_backend_empty</backend_model>
71
+ <sort_order>40</sort_order>
72
+ <show_in_default>1</show_in_default>
73
+ <show_in_website>0</show_in_website>
74
+ <show_in_store>0</show_in_store>
75
+ </reason>
76
+ <other_reason translate="label">
77
+ <label>Other Reason</label>
78
+ <frontend_type>text</frontend_type>
79
+ <backend_model>neklo_core/system_config_backend_empty</backend_model>
80
+ <sort_order>50</sort_order>
81
+ <show_in_default>1</show_in_default>
82
+ <show_in_website>0</show_in_website>
83
+ <show_in_store>0</show_in_store>
84
+ <depends>
85
+ <reason>other</reason>
86
+ </depends>
87
+ </other_reason>
88
+ <message translate="label">
89
+ <label>Message</label>
90
+ <frontend_type>textarea</frontend_type>
91
+ <backend_model>neklo_core/system_config_backend_empty</backend_model>
92
+ <sort_order>60</sort_order>
93
+ <show_in_default>1</show_in_default>
94
+ <show_in_website>0</show_in_website>
95
+ <show_in_store>0</show_in_store>
96
+ </message>
97
+ <button>
98
+ <frontend_model>neklo_core/system_contact_send</frontend_model>
99
+ <sort_order>70</sort_order>
100
+ <show_in_default>1</show_in_default>
101
+ <show_in_website>0</show_in_website>
102
+ <show_in_store>0</show_in_store>
103
+ </button>
104
+ </fields>
105
  </contact>
106
  <newsletter translate="label">
107
  <label>Subscribe to Newsletter</label>
108
  <frontend_type>text</frontend_type>
109
+ <sort_order>30</sort_order>
 
110
  <show_in_default>1</show_in_default>
111
  <show_in_website>0</show_in_website>
112
  <show_in_store>0</show_in_store>
115
  <name translate="label">
116
  <label>Name</label>
117
  <frontend_type>text</frontend_type>
118
+ <backend_model>neklo_core/system_config_backend_empty</backend_model>
119
  <sort_order>10</sort_order>
120
  <show_in_default>1</show_in_default>
121
  <show_in_website>0</show_in_website>
122
  <show_in_store>0</show_in_store>
 
123
  </name>
124
  <email translate="label">
125
  <label>Email</label>
126
  <frontend_type>text</frontend_type>
127
+ <backend_model>neklo_core/system_config_backend_empty</backend_model>
128
  <sort_order>20</sort_order>
129
  <show_in_default>1</show_in_default>
130
  <show_in_website>0</show_in_website>
131
  <show_in_store>0</show_in_store>
 
132
  </email>
133
  <subscribe_button>
134
  <frontend_model>neklo_core/system_newsletter_subscribe</frontend_model>
139
  </subscribe_button>
140
  </fields>
141
  </newsletter>
142
+ <notification>
143
+ <label>Notifications</label>
144
+ <frontend_type>text</frontend_type>
145
+ <sort_order>40</sort_order>
146
+ <show_in_default>1</show_in_default>
147
+ <show_in_website>0</show_in_website>
148
+ <show_in_store>0</show_in_store>
149
+ <fields>
150
+ <type translate="label">
151
+ <label>Receive news about:</label>
152
+ <frontend_type>multiselect</frontend_type>
153
+ <sort_order>10</sort_order>
154
+ <show_in_default>1</show_in_default>
155
+ <show_in_website>0</show_in_website>
156
+ <show_in_store>0</show_in_store>
157
+ <source_model>neklo_core/source_subscription_type</source_model>
158
+ </type>
159
+ </fields>
160
+ </notification>
161
  </groups>
162
  </neklo_core>
163
  </sections>
app/code/community/Neklo/Instagram/Block/Adminhtml/System/Config/Frontend/Oauth.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Neklo_Instagram_Block_Adminhtml_System_Config_Frontend_Oauth extends Mage_Adminhtml_Block_System_Config_Form_Field
4
+ {
5
+ public function render(Varien_Data_Form_Element_Abstract $element)
6
+ {
7
+ $element->setScope(false);
8
+ $element->setCanUseWebsiteValue(false);
9
+ $element->setCanUseDefaultValue(false);
10
+ return parent::render($element);
11
+ }
12
+
13
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
14
+ {
15
+ if (!$this->_getConfig()->isConnected()) {
16
+ $button = $this->getLayout()->createBlock('neklo_instagram_adminhtml/system_config_frontend_oauth_connect', 'neklo_instagram_oauth');
17
+ $button->setTemplate('neklo/instagram/system/config/oauth/connect.phtml');
18
+ } else {
19
+ $button = $this->getLayout()->createBlock('neklo_instagram_adminhtml/system_config_frontend_oauth_disconnect', 'neklo_instagram_oauth');
20
+ $button->setTemplate('neklo/instagram/system/config/oauth/disconnect.phtml');
21
+ }
22
+ $button->setContainerId($element->getContainer()->getHtmlId());
23
+ return $button->toHtml();
24
+ }
25
+
26
+ /**
27
+ * @return Neklo_Instagram_Helper_Config
28
+ */
29
+ protected function _getConfig()
30
+ {
31
+ return Mage::helper('neklo_instagram/config');
32
+ }
33
+ }
app/code/community/Neklo/Instagram/Block/Adminhtml/System/Config/Frontend/Oauth/Connect.php ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Neklo_Instagram_Block_Adminhtml_System_Config_Frontend_Oauth_Connect extends Mage_Adminhtml_Block_Template
4
+ {
5
+ protected $_api = null;
6
+
7
+ /**
8
+ * @return Mage_Adminhtml_Block_Widget_Button
9
+ */
10
+ public function getButton()
11
+ {
12
+ $button = $this->getLayout()->createBlock('adminhtml/widget_button');
13
+ $button
14
+ ->setType('button')
15
+ ->setLabel($this->__('Connect'))
16
+ ->setStyle("width:280px")
17
+ ->setId('neklo_instagram_oauth')
18
+ ;
19
+ return $button;
20
+ }
21
+
22
+ /**
23
+ * @return string
24
+ */
25
+ public function getButtonHtml()
26
+ {
27
+ return $this->getButton()->toHtml();
28
+ }
29
+
30
+ /**
31
+ * @return string
32
+ */
33
+ public function getContainerId()
34
+ {
35
+ return parent::getContainerId();
36
+ }
37
+
38
+ public function getLoginUrl()
39
+ {
40
+ return $this->_getApi()->getLoginUrl(array('basic', 'public_content'));
41
+ }
42
+
43
+ public function getRedirectUrl()
44
+ {
45
+ return Mage::helper("adminhtml")->getUrl("adminhtml/neklo_instagram_api/connect");
46
+ }
47
+
48
+ /**
49
+ * @return Neklo_Instagram_Model_Instagram_Api
50
+ */
51
+ protected function _getApi()
52
+ {
53
+ if ($this->_api === null) {
54
+ $this->_api = $this->_api = Mage::getModel(
55
+ 'neklo_instagram/instagram_api',
56
+ array(
57
+ 'apiKey' => $this->_getConfig()->getClientId(),
58
+ 'apiSecret' => $this->_getConfig()->getClientSecret(),
59
+ 'apiCallback' => $this->getRedirectUrl(),
60
+ )
61
+ );
62
+ }
63
+ return $this->_api;
64
+ }
65
+
66
+ /**
67
+ * @return Neklo_Instagram_Helper_Config
68
+ */
69
+ protected function _getConfig()
70
+ {
71
+ return Mage::helper('neklo_instagram/config');
72
+ }
73
+ }
app/code/community/Neklo/Instagram/Block/Adminhtml/System/Config/Frontend/Oauth/Disconnect.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Neklo_Instagram_Block_Adminhtml_System_Config_Frontend_Oauth_Disconnect extends Mage_Adminhtml_Block_Template
4
+ {
5
+ /**
6
+ * @return Mage_Adminhtml_Block_Widget_Button
7
+ */
8
+ public function getButton()
9
+ {
10
+ $button = $this->getLayout()->createBlock('adminhtml/widget_button');
11
+ $button
12
+ ->setType('button')
13
+ ->setLabel($this->__('Disconnect'))
14
+ ->setStyle("width:280px")
15
+ ->setId('neklo_instagram_oauth')
16
+ ->setClass('delete')
17
+ ;
18
+ return $button;
19
+ }
20
+
21
+ /**
22
+ * @return string
23
+ */
24
+ public function getButtonHtml()
25
+ {
26
+ return $this->getButton()->toHtml();
27
+ }
28
+
29
+ /**
30
+ * @return string
31
+ */
32
+ public function getContainerId()
33
+ {
34
+ return parent::getContainerId();
35
+ }
36
+
37
+ public function getDisconnectUrl()
38
+ {
39
+ return Mage::helper("adminhtml")->getUrl("adminhtml/neklo_instagram_api/disconnect");
40
+ }
41
+ }
app/code/community/Neklo/Instagram/Block/Adminhtml/System/Config/Frontend/Status.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Neklo_Instagram_Block_Adminhtml_System_Config_Frontend_Status extends Mage_Adminhtml_Block_System_Config_Form_Field
4
+ {
5
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
6
+ {
7
+ $element->setBold(true);
8
+
9
+ if ($this->_getConfig()->isConnected()) {
10
+ $element->setValue($this->__('Connected to Instagram'));
11
+ $element->addClass('instagram_status')->addClass('success');
12
+ } else {
13
+ $element->setValue($this->__('Not connected to Instagram'));
14
+ $element->addClass('instagram_status')->addClass('error');
15
+ }
16
+ return '<p id="'. $element->getHtmlId() . '_label" ' . $element->serialize($element->getHtmlAttributes()) . '>' . parent::_getElementHtml($element) . '</p><input id="' . $element->getHtmlId() . '" value="' . (int)$this->_getConfig()->isConnected() . '" type="hidden"/>';
17
+ }
18
+
19
+ protected function _prepareLayout()
20
+ {
21
+ /* @var $head Mage_Page_Block_Html_Head */
22
+ $head = $this->getLayout()->getBlock('head');
23
+ if ($head) {
24
+ $head->addItem('skin_css', 'neklo/instagram/css/styles.css');
25
+ }
26
+ return parent::_prepareLayout();
27
+ }
28
+
29
+ /**
30
+ * @return Neklo_Instagram_Helper_Config
31
+ */
32
+ protected function _getConfig()
33
+ {
34
+ return Mage::helper('neklo_instagram/config');
35
+ }
36
+ }
app/code/community/Neklo/Instagram/Block/Widget/Feed.php CHANGED
@@ -1,47 +1,126 @@
1
- <?php
2
- class Neklo_Instagram_Block_Widget_Feed extends Mage_Core_Block_Template implements Mage_Widget_Block_Interface
3
- {
4
- const NEKLO_WIDGET_CACHE_KEY='NEKLO_WIDGET_INST_CACHE_KEY';
5
-
6
- protected function _construct()
7
- {
8
- $i = Mage::registry(self::NEKLO_WIDGET_CACHE_KEY);
9
- if (!isset($i)) {
10
- $i = 0;
11
- }
12
- {
13
- Mage::unregister(self::NEKLO_WIDGET_CACHE_KEY, $i);
14
- $i++;
15
- }
16
- Mage::register(self::NEKLO_WIDGET_CACHE_KEY, $i);
17
-
18
- $this->setCacheKey(self::NEKLO_WIDGET_CACHE_KEY . '_' . $i);
19
-
20
- $this->setCacheLifetime(Mage::helper('neklo_instagram')->getCacheLifetime());
21
- parent::_construct();
22
- }
23
-
24
- public function getImages() {
25
- switch ($this->getMode()) {
26
- case Neklo_Instagram_Helper_Data::INSTAGRAM_MODE_BY_USER_ID:
27
- if ($this->getUserId()) {
28
- return Mage::getModel('neklo_instagram/instagram')->getUserMedia($this->getUserId(), $this->getLimitItems());
29
- }
30
- break;
31
- case Neklo_Instagram_Helper_Data::INSTAGRAM_MODE_BY_HASHTAG:
32
- if ($this->getHashtag()) {
33
- return Mage::getModel('neklo_instagram/instagram')->getTagMedia(trim($this->getHashtag(), ' #'), $this->getLimitItems());
34
- }
35
- break;
36
- case Neklo_Instagram_Helper_Data::INSTAGRAM_MODE_BY_PRODUCT_HASHTAG:
37
- $product = Mage::registry('current_product');
38
- if ($product && $product->getInstagramHashtag()) {
39
- $hashtag = trim($product->getInstagramHashtag(), ' #');
40
- $this->setHashtag($hashtag);
41
- return Mage::getModel('neklo_instagram/instagram')->getTagMedia($hashtag, $this->getLimitItems());
42
- }
43
- break;
44
- }
45
- return array();
46
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  }
1
+ <?php
2
+ /**
3
+ * @method string getIsEnabled()
4
+ * @method string getMode()
5
+ * @method string getUserId()
6
+ * @method string getUserName()
7
+ * @method string getHashtag()
8
+ * @method string getLimitItems()
9
+ * @method string getImageWidth()
10
+ * @method string getImageHeight()
11
+ */
12
+ class Neklo_Instagram_Block_Widget_Feed extends Mage_Core_Block_Template implements Mage_Widget_Block_Interface
13
+ {
14
+ const CACHE_KEY = 'NEKLO_WIDGET_INSTAGRAM_CACHE_KEY';
15
+
16
+ protected $_api = null;
17
+
18
+ public function setNameInLayout($name)
19
+ {
20
+ $this->addData(
21
+ array(
22
+ 'cache_lifetime' => $this->_getConfig()->getCacheLifetime(),
23
+ 'cache_key' => self::CACHE_KEY . '-' . $name,
24
+ )
25
+ );
26
+ return parent::setNameInLayout($name);
27
+ }
28
+
29
+ public function canShow()
30
+ {
31
+ return $this->_getConfig()->isConnected() && ($this->getIsEnabled() || $this->getIsEnabled() === null);
32
+ }
33
+
34
+ public function getTitle()
35
+ {
36
+ $title = $this->getData('title');
37
+ $hashtag = $this->getHashtag();
38
+ if ($hashtag) {
39
+ $title = str_replace('%s', $hashtag, $title);
40
+ }
41
+ return $title;
42
+ }
43
+
44
+ public function getDescription()
45
+ {
46
+ $description = $this->getData('description');
47
+ $hashtag = $this->getHashtag();
48
+ if ($hashtag) {
49
+ $description = str_replace('%s', $hashtag, $description);
50
+ }
51
+ return $description;
52
+ }
53
+
54
+ public function getImageList()
55
+ {
56
+ switch ($this->getMode()) {
57
+ case Neklo_Instagram_Model_Source_Mode::BY_USER_ID_CODE:
58
+ return $this->_getUserMediaById();
59
+ case Neklo_Instagram_Model_Source_Mode::BY_HASHTAG_CODE:
60
+ return $this->_getTagMedia();
61
+ case Neklo_Instagram_Model_Source_Mode::BY_PRODUCT_HASHTAG_CODE:
62
+ return $this->_getProductTagMedia();
63
+ case Neklo_Instagram_Model_Source_Mode::BY_USER_NAME_CODE:
64
+ return $this->_getUserMediaByName();
65
+ default:
66
+ $imageList = array();
67
+ break;
68
+ }
69
+ return $imageList;
70
+ }
71
+
72
+ protected function _getUserMediaById()
73
+ {
74
+ return $this->_getApi()->getUserMediaById(
75
+ $this->getUserId(), $this->getLimitItems()
76
+ );
77
+ }
78
+
79
+ protected function _getTagMedia()
80
+ {
81
+ if (!$this->getHashtag()) {
82
+ return array();
83
+ }
84
+ return $this->_getApi()->getTagMedia(
85
+ $this->getHashtag(), $this->getLimitItems()
86
+ );
87
+ }
88
+
89
+ protected function _getProductTagMedia()
90
+ {
91
+ $product = Mage::registry('current_product');
92
+ if (!$product || !$product->getId() || !$product->getInstagramHashtag()) {
93
+ return array();
94
+ }
95
+ $this->setHashtag($product->getInstagramHashtag());
96
+ return $this->_getApi()->getTagMedia(
97
+ $this->getHashtag(), $this->getLimitItems()
98
+ );
99
+ }
100
+
101
+ protected function _getUserMediaByName()
102
+ {
103
+ return $this->_getApi()->getUserMediaByName(
104
+ $this->getUserName(), $this->getLimitItems()
105
+ );
106
+ }
107
+
108
+ /**
109
+ * @return Neklo_Instagram_Model_Instagram
110
+ */
111
+ protected function _getApi()
112
+ {
113
+ if ($this->_api === null) {
114
+ $this->_api = Mage::getModel('neklo_instagram/instagram');
115
+ }
116
+ return $this->_api;
117
+ }
118
+
119
+ /**
120
+ * @return Neklo_Instagram_Helper_Config
121
+ */
122
+ protected function _getConfig()
123
+ {
124
+ return Mage::helper('neklo_instagram/config');
125
+ }
126
  }
app/code/community/Neklo/Instagram/Helper/Config.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Neklo_Instagram_Helper_Config extends Mage_Core_Helper_Abstract
4
+ {
5
+ const GENERAL_CACHE_LIFETIME = 'neklo_instagram/general/cache_lifetime';
6
+
7
+ const API_ACCESS_TOKEN = 'neklo_instagram/api/access_token';
8
+ const API_CLIENT_ID = 'neklo_instagram/api/client_id';
9
+ const API_CLIENT_SECRET = 'neklo_instagram/api/client_secret';
10
+
11
+ public function getCacheLifetime($store = null)
12
+ {
13
+ return (int)Mage::getStoreConfig(self::GENERAL_CACHE_LIFETIME, $store);
14
+ }
15
+
16
+ public function connect($accessToken)
17
+ {
18
+ $encryptedAccessToken = Mage::helper('core')->encrypt($accessToken);
19
+ $this->_saveConfig(self::API_ACCESS_TOKEN, $encryptedAccessToken);
20
+
21
+ // reinit configuration cache
22
+ Mage::getConfig()->reinit();
23
+ }
24
+
25
+ public function disconnect()
26
+ {
27
+ $encryptedAccessToken = Mage::helper('core')->encrypt('');
28
+ $this->_saveConfig(self::API_ACCESS_TOKEN, $encryptedAccessToken);
29
+
30
+ // reinit configuration cache
31
+ Mage::getConfig()->reinit();
32
+ }
33
+
34
+ public function isConnected()
35
+ {
36
+ return Mage::getStoreConfigFlag(self::API_ACCESS_TOKEN);
37
+ }
38
+
39
+ public function getAccessToken($store = null)
40
+ {
41
+ return Mage::helper('core')->decrypt(Mage::getStoreConfig(self::API_ACCESS_TOKEN, $store));
42
+ }
43
+
44
+ public function getClientId($store = null)
45
+ {
46
+ return Mage::getStoreConfig(self::API_CLIENT_ID, $store);
47
+ }
48
+
49
+ public function getClientSecret($store = null)
50
+ {
51
+ return Mage::getStoreConfig(self::API_CLIENT_SECRET, $store);
52
+ }
53
+
54
+ protected function _saveConfig($path, $value, $scope = 'default', $scopeId = 0)
55
+ {
56
+ $configModel = Mage::getModel('core/config');
57
+ $configModel->saveConfig($path, $value, $scope, $scopeId);
58
+ }
59
+ }
app/code/community/Neklo/Instagram/Helper/Data.php CHANGED
@@ -1,15 +1,27 @@
1
- <?php
2
-
3
- class Neklo_Instagram_Helper_Data extends Mage_Core_Helper_Abstract
4
- {
5
- const INSTAGRAM_MODE_BY_USER_ID = 1;
6
- const INSTAGRAM_MODE_BY_HASHTAG = 2;
7
- const INSTAGRAM_MODE_BY_PRODUCT_HASHTAG = 3;
8
-
9
- public function getCacheLifetime()
10
- {
11
- return (int)Mage::getStoreConfig(
12
- 'neklo_instagram/general/cache_lifetime'
13
- );
14
- }
15
- }
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Neklo_Instagram_Helper_Data extends Mage_Core_Helper_Abstract
4
+ {
5
+ public function __()
6
+ {
7
+ $args = func_get_args();
8
+ if ($args[0] == '{{connect_hint}}') {
9
+ if ($this->_getConfig()->isConnected()) {
10
+ return '';
11
+ }
12
+ $args[0] = 'Add <b>%s</b> to redirect urls for Instagram application';
13
+ $args[1] = Mage::helper("adminhtml")->getUrl("adminhtml/neklo_instagram_api/connect");
14
+ }
15
+ $expr = new Mage_Core_Model_Translate_Expr(array_shift($args), $this->_getModuleName());
16
+ array_unshift($args, $expr);
17
+ return Mage::app()->getTranslator()->translate($args);
18
+ }
19
+
20
+ /**
21
+ * @return Neklo_Instagram_Helper_Config
22
+ */
23
+ protected function _getConfig()
24
+ {
25
+ return Mage::helper('neklo_instagram/config');
26
+ }
27
+ }
app/code/community/Neklo/Instagram/Model/Instagram.php CHANGED
@@ -1,103 +1,122 @@
1
- <?php
2
-
3
- class Neklo_Instagram_Model_Instagram
4
- {
5
- const CLIENT_ID = '3a700f8477174a2da05895ee57b829f9';
6
-
7
- protected $_api = null;
8
-
9
- /**
10
- * Returns Instagram API model.
11
- *
12
- * @return Neklo_Instagram_Model_Instagram_Api
13
- */
14
- public function getAPI()
15
- {
16
- if ($this->_api) {
17
- return $this->_api;
18
- }
19
- $this->_api = Mage::getModel('neklo_instagram/instagram_api', self::CLIENT_ID);
20
- return $this->_api;
21
- }
22
-
23
- public function getTagMedia($name, $limit = 0)
24
- {
25
- try {
26
- $response = $this->getAPI()->getTagMedia($name, $limit);
27
- } catch (Exception $e) {
28
- Mage::logException($e);
29
- return array();
30
- }
31
- $collection = new Varien_Data_Collection();
32
- if (!isset($response->data) || !is_array($response->data)) {
33
- return $collection;
34
- }
35
-
36
- foreach ($response->data as $item) {
37
- if (!isset($item->images->low_resolution->url)) {
38
- continue;
39
- }
40
-
41
- $image = new Varien_Object();
42
- $image->setUrl($item->images->low_resolution->url);
43
-
44
- if (isset($item->caption->text)) {
45
- $image->setName($item->caption->text);
46
- }
47
-
48
- if (isset($item->link)) {
49
- $image->setLink($item->link);
50
- }
51
-
52
- $collection->addItem($image);
53
- }
54
-
55
- return $collection;
56
- }
57
-
58
- /**
59
- * @param int $id
60
- *
61
- * @return Variend_Data_Collection
62
- */
63
- public function getUserMedia($id, $limit = 0)
64
- {
65
- try {
66
- $response = $this->getAPI()->getUserMedia($id, $limit);
67
- } catch (Exception $e) {
68
- Mage::logException($e);
69
- return array();
70
- }
71
-
72
- $collection = new Varien_Data_Collection();
73
- if (!isset($response->data) || !is_array($response->data)) {
74
- return $collection;
75
- }
76
-
77
- foreach ($response->data as $item) {
78
- if (!isset($item->images->low_resolution->url)) {
79
- continue;
80
- }
81
-
82
- $image = new Varien_Object();
83
- $image->setUrl($item->images->low_resolution->url);
84
-
85
- if (isset($item->caption->text)) {
86
- $image->setName($item->caption->text);
87
- }
88
-
89
- if (isset($item->link)) {
90
- $image->setLink($item->link);
91
- }
92
-
93
- $collection->addItem($image);
94
- }
95
-
96
- return $collection;
97
- }
98
-
99
- protected function getHelper()
100
- {
101
- return Mage::helper('neklo_instagram');
102
- }
103
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Neklo_Instagram_Model_Instagram
4
+ {
5
+ protected $_api = null;
6
+
7
+ /**
8
+ * Returns Instagram API model.
9
+ *
10
+ * @return Neklo_Instagram_Model_Instagram_Api
11
+ */
12
+ public function getApi()
13
+ {
14
+ if ($this->_api === null) {
15
+ $this->_api = Mage::getModel(
16
+ 'neklo_instagram/instagram_api',
17
+ $this->_getConfig()->getAccessToken()
18
+ );
19
+ }
20
+ return $this->_api;
21
+ }
22
+
23
+ /**
24
+ * @param string $name
25
+ * @param int $limit
26
+ *
27
+ * @return Varien_Data_Collection
28
+ */
29
+ public function getTagMedia($name, $limit = 0)
30
+ {
31
+ $collection = new Varien_Data_Collection();
32
+ try {
33
+ $response = $this->getApi()->getTagMedia($name, $limit);
34
+ } catch (Exception $e) {
35
+ Mage::logException($e);
36
+ return $collection;
37
+ }
38
+ if (!isset($response->data) || !is_array($response->data)) {
39
+ return $collection;
40
+ }
41
+ foreach ($response->data as $item) {
42
+ if (!isset($item->images->low_resolution->url)) {
43
+ continue;
44
+ }
45
+ $image = new Varien_Object();
46
+ $image->setUrl($item->images->low_resolution->url);
47
+ if (isset($item->caption->text)) {
48
+ $image->setName($item->caption->text);
49
+ }
50
+ if (isset($item->link)) {
51
+ $image->setLink($item->link);
52
+ }
53
+ $collection->addItem($image);
54
+ }
55
+ return $collection;
56
+ }
57
+
58
+ /**
59
+ * @param string $userId
60
+ * @param int $limit
61
+ *
62
+ * @return Varien_Data_Collection
63
+ */
64
+ public function getUserMediaById($userId, $limit = 0)
65
+ {
66
+ $collection = new Varien_Data_Collection();
67
+ try {
68
+ $response = $this->getApi()->getUserMedia($userId, $limit);
69
+ } catch (Exception $e) {
70
+ Mage::logException($e);
71
+ return $collection;
72
+ }
73
+ if (!isset($response->data) || !is_array($response->data)) {
74
+ return $collection;
75
+ }
76
+ foreach ($response->data as $item) {
77
+ if (!isset($item->images->low_resolution->url)) {
78
+ continue;
79
+ }
80
+ $image = new Varien_Object();
81
+ $image->setUrl($item->images->low_resolution->url);
82
+ if (isset($item->caption->text)) {
83
+ $image->setName($item->caption->text);
84
+ }
85
+ if (isset($item->link)) {
86
+ $image->setLink($item->link);
87
+ }
88
+ $collection->addItem($image);
89
+ }
90
+ return $collection;
91
+ }
92
+
93
+ /**
94
+ * @param string $userName
95
+ * @param int $limit
96
+ *
97
+ * @return Varien_Data_Collection
98
+ */
99
+ public function getUserMediaByName($userName, $limit = 0)
100
+ {
101
+ $collection = new Varien_Data_Collection();
102
+ try {
103
+ $response = $this->getApi()->searchUser($userName);
104
+ } catch (Exception $e) {
105
+ Mage::logException($e);
106
+ return $collection;
107
+ }
108
+ if (!isset($response->data) || !is_array($response->data) || !count($response->data)) {
109
+ return $collection;
110
+ }
111
+ $user = current($response->data);
112
+ return $this->getUserMediaById($user->id, $limit);
113
+ }
114
+
115
+ /**
116
+ * @return Neklo_Instagram_Helper_Config
117
+ */
118
+ protected function _getConfig()
119
+ {
120
+ return Mage::helper('neklo_instagram/config');
121
+ }
122
+ }
app/code/community/Neklo/Instagram/Model/Instagram/Api.php CHANGED
@@ -1,568 +1,840 @@
1
- <?php
2
- /**
3
- * Instagram API class
4
- * API Documentation: http://instagram.com/developer/
5
- * Class Documentation: https://github.com/cosenary/Instagram-PHP-API/tree/dev
6
- *
7
- * @author Christian Metz
8
- * @since 30.10.2011
9
- * @copyright Christian Metz - MetzWeb Networks 2011-2014
10
- * @version 2.1
11
- * @license BSD http://www.opensource.org/licenses/bsd-license.php
12
- */
13
- class Neklo_Instagram_Model_Instagram_Api {
14
-
15
- /**
16
- * The API base URL
17
- */
18
- const API_URL = 'https://api.instagram.com/v1/';
19
-
20
- /**
21
- * The API OAuth URL
22
- */
23
- const API_OAUTH_URL = 'https://api.instagram.com/oauth/authorize';
24
-
25
- /**
26
- * The OAuth token URL
27
- */
28
- const API_OAUTH_TOKEN_URL = 'https://api.instagram.com/oauth/access_token';
29
-
30
- /**
31
- * The Instagram API Key
32
- *
33
- * @var string
34
- */
35
- private $_apikey;
36
-
37
- /**
38
- * The Instagram OAuth API secret
39
- *
40
- * @var string
41
- */
42
- private $_apisecret;
43
-
44
- /**
45
- * The callback URL
46
- *
47
- * @var string
48
- */
49
- private $_callbackurl;
50
-
51
- /**
52
- * The user access token
53
- *
54
- * @var string
55
- */
56
- private $_accesstoken;
57
-
58
- /**
59
- * Available scopes
60
- *
61
- * @var array
62
- */
63
- private $_scopes = array('basic', 'likes', 'comments', 'relationships');
64
-
65
- /**
66
- * Available actions
67
- *
68
- * @var array
69
- */
70
- private $_actions = array('follow', 'unfollow', 'block', 'unblock', 'approve', 'deny');
71
-
72
- /**
73
- * Default constructor
74
- *
75
- * @param array|string $config Instagram configuration data
76
- * @return void
77
- */
78
- public function __construct($config) {
79
- if (true === is_array($config)) {
80
- // if you want to access user data
81
- $this->setApiKey($config['apiKey']);
82
- $this->setApiSecret($config['apiSecret']);
83
- $this->setApiCallback($config['apiCallback']);
84
- } else if (true === is_string($config)) {
85
- // if you only want to access public data
86
- $this->setApiKey($config);
87
- } else {
88
- throw new Exception("Error: __construct() - Configuration data is missing.");
89
- }
90
- }
91
-
92
- /**
93
- * Generates the OAuth login URL
94
- *
95
- * @param array [optional] $scope Requesting additional permissions
96
- * @return string Instagram OAuth login URL
97
- */
98
- public function getLoginUrl($scope = array('basic')) {
99
- if (is_array($scope) && count(array_intersect($scope, $this->_scopes)) === count($scope)) {
100
- return self::API_OAUTH_URL . '?client_id=' . $this->getApiKey() . '&redirect_uri=' . urlencode($this->getApiCallback()) . '&scope=' . implode('+', $scope) . '&response_type=code';
101
- } else {
102
- throw new Exception("Error: getLoginUrl() - The parameter isn't an array or invalid scope permissions used.");
103
- }
104
- }
105
-
106
- /**
107
- * Search for a user
108
- *
109
- * @param string $name Instagram username
110
- * @param integer [optional] $limit Limit of returned results
111
- * @return mixed
112
- */
113
- public function searchUser($name, $limit = 0) {
114
- return $this->_makeCall('users/search', false, array('q' => $name, 'count' => $limit));
115
- }
116
-
117
- /**
118
- * Get user info
119
- *
120
- * @param integer [optional] $id Instagram user ID
121
- * @return mixed
122
- */
123
- public function getUser($id = 0) {
124
- $auth = false;
125
- if ($id === 0 && isset($this->_accesstoken)) { $id = 'self'; $auth = true; }
126
- return $this->_makeCall('users/' . $id, $auth);
127
- }
128
-
129
- /**
130
- * Get user activity feed
131
- *
132
- * @param integer [optional] $limit Limit of returned results
133
- * @return mixed
134
- */
135
- public function getUserFeed($limit = 0) {
136
- return $this->_makeCall('users/self/feed', true, array('count' => $limit));
137
- }
138
-
139
- /**
140
- * Get user recent media
141
- *
142
- * @param integer [optional] $id Instagram user ID
143
- * @param integer [optional] $limit Limit of returned results
144
- * @return mixed
145
- */
146
- public function getUserMedia($id = 'self', $limit = 0) {
147
- return $this->_makeCall('users/' . $id . '/media/recent', ($id === 'self'), array('count' => $limit));
148
- }
149
-
150
- /**
151
- * Get the liked photos of a user
152
- *
153
- * @param integer [optional] $limit Limit of returned results
154
- * @return mixed
155
- */
156
- public function getUserLikes($limit = 0) {
157
- return $this->_makeCall('users/self/media/liked', true, array('count' => $limit));
158
- }
159
-
160
- /**
161
- * Get the list of users this user follows
162
- *
163
- * @param integer [optional] $id Instagram user ID
164
- * @param integer [optional] $limit Limit of returned results
165
- * @return mixed
166
- */
167
- public function getUserFollows($id = 'self', $limit = 0) {
168
- return $this->_makeCall('users/' . $id . '/follows', true, array('count' => $limit));
169
- }
170
-
171
- /**
172
- * Get the list of users this user is followed by
173
- *
174
- * @param integer [optional] $id Instagram user ID
175
- * @param integer [optional] $limit Limit of returned results
176
- * @return mixed
177
- */
178
- public function getUserFollower($id = 'self', $limit = 0) {
179
- return $this->_makeCall('users/' . $id . '/followed-by', true, array('count' => $limit));
180
- }
181
-
182
- /**
183
- * Get information about a relationship to another user
184
- *
185
- * @param integer $id Instagram user ID
186
- * @return mixed
187
- */
188
- public function getUserRelationship($id) {
189
- return $this->_makeCall('users/' . $id . '/relationship', true);
190
- }
191
-
192
- /**
193
- * Modify the relationship between the current user and the target user
194
- *
195
- * @param string $action Action command (follow/unfollow/block/unblock/approve/deny)
196
- * @param integer $user Target user ID
197
- * @return mixed
198
- */
199
- public function modifyRelationship($action, $user) {
200
- if (true === in_array($action, $this->_actions) && isset($user)) {
201
- return $this->_makeCall('users/' . $user . '/relationship', true, array('action' => $action), 'POST');
202
- }
203
- throw new Exception("Error: modifyRelationship() | This method requires an action command and the target user id.");
204
- }
205
-
206
- /**
207
- * Search media by its location
208
- *
209
- * @param float $lat Latitude of the center search coordinate
210
- * @param float $lng Longitude of the center search coordinate
211
- * @param integer [optional] $distance Distance in metres (default is 1km (distance=1000), max. is 5km)
212
- * @param long [optional] $minTimestamp Media taken later than this timestamp (default: 5 days ago)
213
- * @param long [optional] $maxTimestamp Media taken earlier than this timestamp (default: now)
214
- * @return mixed
215
- */
216
- public function searchMedia($lat, $lng, $distance = 1000, $minTimestamp = NULL, $maxTimestamp = NULL) {
217
- return $this->_makeCall('media/search', false, array('lat' => $lat, 'lng' => $lng, 'distance' => $distance, 'min_timestamp' => $minTimestamp, 'max_timestamp' => $maxTimestamp));
218
- }
219
-
220
- /**
221
- * Get media by its id
222
- *
223
- * @param integer $id Instagram media ID
224
- * @return mixed
225
- */
226
- public function getMedia($id) {
227
- return $this->_makeCall('media/' . $id);
228
- }
229
-
230
- /**
231
- * Get the most popular media
232
- *
233
- * @return mixed
234
- */
235
- public function getPopularMedia() {
236
- return $this->_makeCall('media/popular');
237
- }
238
-
239
- /**
240
- * Search for tags by name
241
- *
242
- * @param string $name Valid tag name
243
- * @return mixed
244
- */
245
- public function searchTags($name) {
246
- return $this->_makeCall('tags/search', false, array('q' => $name));
247
- }
248
-
249
- /**
250
- * Get info about a tag
251
- *
252
- * @param string $name Valid tag name
253
- * @return mixed
254
- */
255
- public function getTag($name) {
256
- return $this->_makeCall('tags/' . $name);
257
- }
258
-
259
- /**
260
- * Get a recently tagged media
261
- *
262
- * @param string $name Valid tag name
263
- * @param integer [optional] $limit Limit of returned results
264
- * @return mixed
265
- */
266
- public function getTagMedia($name, $limit = 0) {
267
- return $this->_makeCall('tags/' . $name . '/media/recent', false, array('count' => $limit));
268
- }
269
-
270
- /**
271
- * Get a list of users who have liked this media
272
- *
273
- * @param integer $id Instagram media ID
274
- * @return mixed
275
- */
276
- public function getMediaLikes($id) {
277
- return $this->_makeCall('media/' . $id . '/likes', true);
278
- }
279
-
280
- /**
281
- * Get a list of comments for this media
282
- *
283
- * @param integer $id Instagram media ID
284
- * @return mixed
285
- */
286
- public function getMediaComments($id) {
287
- return $this->_makeCall('media/' . $id . '/comments', false);
288
- }
289
-
290
- /**
291
- * Add a comment on a media
292
- *
293
- * @param integer $id Instagram media ID
294
- * @param string $text Comment content
295
- * @return mixed
296
- */
297
- public function addMediaComment($id, $text) {
298
- return $this->_makeCall('media/' . $id . '/comments', true, array('text' => $text), 'POST');
299
- }
300
-
301
- /**
302
- * Remove user comment on a media
303
- *
304
- * @param integer $id Instagram media ID
305
- * @param string $commentID User comment ID
306
- * @return mixed
307
- */
308
- public function deleteMediaComment($id, $commentID) {
309
- return $this->_makeCall('media/' . $id . '/comments/' . $commentID, true, null, 'DELETE');
310
- }
311
-
312
- /**
313
- * Set user like on a media
314
- *
315
- * @param integer $id Instagram media ID
316
- * @return mixed
317
- */
318
- public function likeMedia($id) {
319
- return $this->_makeCall('media/' . $id . '/likes', true, null, 'POST');
320
- }
321
-
322
- /**
323
- * Remove user like on a media
324
- *
325
- * @param integer $id Instagram media ID
326
- * @return mixed
327
- */
328
- public function deleteLikedMedia($id) {
329
- return $this->_makeCall('media/' . $id . '/likes', true, null, 'DELETE');
330
- }
331
-
332
- /**
333
- * Get information about a location
334
- *
335
- * @param integer $id Instagram location ID
336
- * @return mixed
337
- */
338
- public function getLocation($id) {
339
- return $this->_makeCall('locations/' . $id, false);
340
- }
341
-
342
- /**
343
- * Get recent media from a given location
344
- *
345
- * @param integer $id Instagram location ID
346
- * @return mixed
347
- */
348
- public function getLocationMedia($id) {
349
- return $this->_makeCall('locations/' . $id . '/media/recent', false);
350
- }
351
-
352
- /**
353
- * Get recent media from a given location
354
- *
355
- * @param float $lat Latitude of the center search coordinate
356
- * @param float $lng Longitude of the center search coordinate
357
- * @param integer [optional] $distance Distance in meter (max. distance: 5km = 5000)
358
- * @return mixed
359
- */
360
- public function searchLocation($lat, $lng, $distance = 1000) {
361
- return $this->_makeCall('locations/search', false, array('lat' => $lat, 'lng' => $lng, 'distance' => $distance));
362
- }
363
-
364
- /**
365
- * Pagination feature
366
- *
367
- * @param object $obj Instagram object returned by a method
368
- * @param integer $limit Limit of returned results
369
- * @return mixed
370
- */
371
- public function pagination($obj, $limit = 0) {
372
- if (true === is_object($obj) && !is_null($obj->pagination)) {
373
- if (!isset($obj->pagination->next_url)) {
374
- return;
375
- }
376
- $apiCall = explode('?', $obj->pagination->next_url);
377
- if (count($apiCall) < 2) {
378
- return;
379
- }
380
- $function = str_replace(self::API_URL, '', $apiCall[0]);
381
- $auth = (strpos($apiCall[1], 'access_token') !== false);
382
- if (isset($obj->pagination->next_max_id)) {
383
- return $this->_makeCall($function, $auth, array('max_id' => $obj->pagination->next_max_id, 'count' => $limit));
384
- } else {
385
- return $this->_makeCall($function, $auth, array('cursor' => $obj->pagination->next_cursor, 'count' => $limit));
386
- }
387
- } else {
388
- throw new Exception("Error: pagination() | This method doesn't support pagination.");
389
- }
390
- }
391
-
392
- /**
393
- * Get the OAuth data of a user by the returned callback code
394
- *
395
- * @param string $code OAuth2 code variable (after a successful login)
396
- * @param boolean [optional] $token If it's true, only the access token will be returned
397
- * @return mixed
398
- */
399
- public function getOAuthToken($code, $token = false) {
400
- $apiData = array(
401
- 'grant_type' => 'authorization_code',
402
- 'client_id' => $this->getApiKey(),
403
- 'client_secret' => $this->getApiSecret(),
404
- 'redirect_uri' => $this->getApiCallback(),
405
- 'code' => $code
406
- );
407
-
408
- $result = $this->_makeOAuthCall($apiData);
409
- return (false === $token) ? $result : $result->access_token;
410
- }
411
-
412
- /**
413
- * The call operator
414
- *
415
- * @param string $function API resource path
416
- * @param array [optional] $params Additional request parameters
417
- * @param boolean [optional] $auth Whether the function requires an access token
418
- * @param string [optional] $method Request type GET|POST
419
- * @return mixed
420
- */
421
- protected function _makeCall($function, $auth = false, $params = null, $method = 'GET') {
422
- if (false === $auth) {
423
- // if the call doesn't requires authentication
424
- $authMethod = '?client_id=' . $this->getApiKey();
425
- } else {
426
- // if the call needs an authenticated user
427
- if (true === isset($this->_accesstoken)) {
428
- $authMethod = '?access_token=' . $this->getAccessToken();
429
- } else {
430
- throw new Exception("Error: _makeCall() | $function - This method requires an authenticated users access token.");
431
- }
432
- }
433
-
434
- if (isset($params) && is_array($params)) {
435
- $paramString = '&' . http_build_query($params);
436
- } else {
437
- $paramString = null;
438
- }
439
-
440
- $apiCall = self::API_URL . $function . $authMethod . (('GET' === $method) ? $paramString : null);
441
-
442
- $ch = curl_init();
443
- curl_setopt($ch, CURLOPT_URL, $apiCall);
444
- curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json'));
445
- curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
446
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
447
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
448
-
449
- if ('POST' === $method) {
450
- curl_setopt($ch, CURLOPT_POST, count($params));
451
- curl_setopt($ch, CURLOPT_POSTFIELDS, ltrim($paramString, '&'));
452
- } else if ('DELETE' === $method) {
453
- curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
454
- }
455
-
456
- $jsonData = curl_exec($ch);
457
- if (false === $jsonData) {
458
- throw new Exception("Error: _makeCall() - cURL error: " . curl_error($ch));
459
- }
460
- curl_close($ch);
461
-
462
- return json_decode($jsonData);
463
- }
464
-
465
- /**
466
- * The OAuth call operator
467
- *
468
- * @param array $apiData The post API data
469
- * @return mixed
470
- */
471
- private function _makeOAuthCall($apiData) {
472
- $apiHost = self::API_OAUTH_TOKEN_URL;
473
-
474
- $ch = curl_init();
475
- curl_setopt($ch, CURLOPT_URL, $apiHost);
476
- curl_setopt($ch, CURLOPT_POST, count($apiData));
477
- curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($apiData));
478
- curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json'));
479
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
480
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
481
-
482
- $jsonData = curl_exec($ch);
483
- if (false === $jsonData) {
484
- throw new Exception("Error: _makeOAuthCall() - cURL error: " . curl_error($ch));
485
- }
486
- curl_close($ch);
487
-
488
- return json_decode($jsonData);
489
- }
490
-
491
- /**
492
- * Access Token Setter
493
- *
494
- * @param object|string $data
495
- * @return void
496
- */
497
- public function setAccessToken($data) {
498
- (true === is_object($data)) ? $token = $data->access_token : $token = $data;
499
- $this->_accesstoken = $token;
500
- }
501
-
502
- /**
503
- * Access Token Getter
504
- *
505
- * @return string
506
- */
507
- public function getAccessToken() {
508
- return $this->_accesstoken;
509
- }
510
-
511
- /**
512
- * API-key Setter
513
- *
514
- * @param string $apiKey
515
- * @return void
516
- */
517
- public function setApiKey($apiKey) {
518
- $this->_apikey = $apiKey;
519
- }
520
-
521
- /**
522
- * API Key Getter
523
- *
524
- * @return string
525
- */
526
- public function getApiKey() {
527
- return $this->_apikey;
528
- }
529
-
530
- /**
531
- * API Secret Setter
532
- *
533
- * @param string $apiSecret
534
- * @return void
535
- */
536
- public function setApiSecret($apiSecret) {
537
- $this->_apisecret = $apiSecret;
538
- }
539
-
540
- /**
541
- * API Secret Getter
542
- *
543
- * @return string
544
- */
545
- public function getApiSecret() {
546
- return $this->_apisecret;
547
- }
548
-
549
- /**
550
- * API Callback URL Setter
551
- *
552
- * @param string $apiCallback
553
- * @return void
554
- */
555
- public function setApiCallback($apiCallback) {
556
- $this->_callbackurl = $apiCallback;
557
- }
558
-
559
- /**
560
- * API Callback URL Getter
561
- *
562
- * @return string
563
- */
564
- public function getApiCallback() {
565
- return $this->_callbackurl;
566
- }
567
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
568
  }
1
+ <?php
2
+ /**
3
+ * Instagram API class
4
+ *
5
+ * API Documentation: http://instagram.com/developer/
6
+ * Class Documentation: https://github.com/cosenary/Instagram-PHP-API
7
+ *
8
+ * @author Christian Metz
9
+ * @since 30.10.2011
10
+ * @copyright Christian Metz - MetzWeb Networks 2011-2014
11
+ * @version 2.2
12
+ * @license BSD http://www.opensource.org/licenses/bsd-license.php
13
+ * @codingStandardsIgnoreFile
14
+ * @SuppressWarnings(PHPMD)
15
+ */
16
+ class Neklo_Instagram_Model_Instagram_Api
17
+ {
18
+ /**
19
+ * The API base URL.
20
+ */
21
+ const API_URL = 'https://api.instagram.com/v1/';
22
+
23
+ /**
24
+ * The API OAuth URL.
25
+ */
26
+ const API_OAUTH_URL = 'https://api.instagram.com/oauth/authorize';
27
+
28
+ /**
29
+ * The OAuth token URL.
30
+ */
31
+ const API_OAUTH_TOKEN_URL = 'https://api.instagram.com/oauth/access_token';
32
+
33
+ /**
34
+ * The Instagram API Key.
35
+ *
36
+ * @var string
37
+ */
38
+ private $_apikey;
39
+
40
+ /**
41
+ * The Instagram OAuth API secret.
42
+ *
43
+ * @var string
44
+ */
45
+ private $_apisecret;
46
+
47
+ /**
48
+ * The callback URL.
49
+ *
50
+ * @var string
51
+ */
52
+ private $_callbackurl;
53
+
54
+ /**
55
+ * The user access token.
56
+ *
57
+ * @var string
58
+ */
59
+ private $_accesstoken;
60
+
61
+ /**
62
+ * Whether a signed header should be used.
63
+ *
64
+ * @var bool
65
+ */
66
+ private $_signedheader = false;
67
+
68
+ /**
69
+ * Available scopes.
70
+ *
71
+ * @var string[]
72
+ */
73
+ private $_scopes = array('basic', 'likes', 'comments', 'relationships', 'public_content', 'follower_list');
74
+
75
+ /**
76
+ * Available actions.
77
+ *
78
+ * @var string[]
79
+ */
80
+ private $_actions = array('follow', 'unfollow', 'approve', 'ignore');
81
+
82
+ /**
83
+ * Rate limit.
84
+ *
85
+ * @var int
86
+ */
87
+ private $_xRateLimitRemaining;
88
+
89
+ /**
90
+ * Default constructor.
91
+ *
92
+ * @param array|string $config Instagram configuration data
93
+ *
94
+ * @throws Exception
95
+ */
96
+ public function __construct($config)
97
+ {
98
+ if (is_array($config)) {
99
+ $this->setApiKey($config['apiKey']);
100
+ $this->setApiSecret($config['apiSecret']);
101
+ $this->setApiCallback($config['apiCallback']);
102
+ } elseif (is_string($config)) {
103
+ $this->setAccessToken($config);
104
+ } else {
105
+ throw new Exception('Error: __construct() - Configuration data is missing.');
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Generates the OAuth login URL.
111
+ *
112
+ * @param string[] $scopes Requesting additional permissions
113
+ *
114
+ * @return string Instagram OAuth login URL
115
+ *
116
+ * @throws Exception
117
+ */
118
+ public function getLoginUrl($scopes = array('basic'))
119
+ {
120
+ if (is_array($scopes) && count(array_intersect($scopes, $this->_scopes)) === count($scopes)) {
121
+ return self::API_OAUTH_URL . '?client_id=' . $this->getApiKey() . '&redirect_uri=' . urlencode($this->getApiCallback()) . '&scope=' . implode('+',
122
+ $scopes) . '&response_type=code';
123
+ }
124
+
125
+ throw new Exception("Error: getLoginUrl() - The parameter isn't an array or invalid scope permissions used.");
126
+ }
127
+
128
+ /**
129
+ * Search for a user.
130
+ *
131
+ * @param string $name Instagram username
132
+ * @param int $limit Limit of returned results
133
+ *
134
+ * @return mixed
135
+ */
136
+ public function searchUser($name, $limit = 0)
137
+ {
138
+ $params = array();
139
+
140
+ $params['q'] = $name;
141
+ if ($limit > 0) {
142
+ $params['count'] = $limit;
143
+ }
144
+
145
+ return $this->_makeCall('users/search', $params);
146
+ }
147
+
148
+ /**
149
+ * Get user info.
150
+ *
151
+ * @param int $id Instagram user ID
152
+ *
153
+ * @return mixed
154
+ */
155
+ public function getUser($id = 0)
156
+ {
157
+ if ($id === 0) {
158
+ $id = 'self';
159
+ }
160
+
161
+ return $this->_makeCall('users/' . $id);
162
+ }
163
+
164
+ /**
165
+ * Get user recent media.
166
+ *
167
+ * @param int|string $id Instagram user ID
168
+ * @param int $limit Limit of returned results
169
+ * @param int $min_id Return media later than this min_id
170
+ * @param int $max_id Return media earlier than this max_id
171
+ *
172
+ * @return mixed
173
+ */
174
+ public function getUserMedia($id = 'self', $limit = 0, $min_id = null, $max_id = null)
175
+ {
176
+ $params = array();
177
+
178
+ if ($limit > 0) {
179
+ $params['count'] = $limit;
180
+ }
181
+ if (isset($min_id)) {
182
+ $params['min_id'] = $min_id;
183
+ }
184
+ if (isset($max_id)) {
185
+ $params['max_id'] = $max_id;
186
+ }
187
+
188
+ return $this->_makeCall('users/' . $id . '/media/recent', $params);
189
+ }
190
+
191
+ /**
192
+ * Get the liked photos of a user.
193
+ *
194
+ * @param int $limit Limit of returned results
195
+ * @param int $max_like_id Return media liked before this id
196
+ *
197
+ * @return mixed
198
+ */
199
+ public function getUserLikes($limit = 0, $max_like_id = null)
200
+ {
201
+ $params = array();
202
+
203
+ if ($limit > 0) {
204
+ $params['count'] = $limit;
205
+ }
206
+ if (isset($max_id)) {
207
+ $params['max_like_id'] = $max_like_id;
208
+ }
209
+
210
+ return $this->_makeCall('users/self/media/liked', $params);
211
+ }
212
+
213
+ /**
214
+ * DEPRECATED
215
+ * Get the list of users this user follows
216
+ *
217
+ * @param int|string $id Instagram user ID.
218
+ * @param int $limit Limit of returned results
219
+ *
220
+ * @return void
221
+ */
222
+ public function getUserFollows($id = 'self', $limit = 0)
223
+ {
224
+ $this->getFollows();
225
+ }
226
+
227
+ /**
228
+ * Get the list of users the authenticated user follows.
229
+ *
230
+ * @return mixed
231
+ */
232
+ public function getFollows()
233
+ {
234
+ return $this->_makeCall('users/self/follows');
235
+ }
236
+
237
+ /**
238
+ * DEPRECATED
239
+ * Get the list of users this user is followed by.
240
+ *
241
+ * @param int|string $id Instagram user ID
242
+ * @param int $limit Limit of returned results
243
+ *
244
+ * @return void
245
+ */
246
+ public function getUserFollower($id = 'self', $limit = 0)
247
+ {
248
+ $this->getFollower();
249
+ }
250
+
251
+ /**
252
+ * Get the list of users this user is followed by.
253
+ *
254
+ * @return mixed
255
+ */
256
+ public function getFollower()
257
+ {
258
+ return $this->_makeCall('users/self/followed-by');
259
+ }
260
+
261
+ /**
262
+ * Get information about a relationship to another user.
263
+ *
264
+ * @param int $id Instagram user ID
265
+ *
266
+ * @return mixed
267
+ */
268
+ public function getUserRelationship($id)
269
+ {
270
+ return $this->_makeCall('users/' . $id . '/relationship');
271
+ }
272
+
273
+ /**
274
+ * Get the value of X-RateLimit-Remaining header field.
275
+ *
276
+ * @return int X-RateLimit-Remaining API calls left within 1 hour
277
+ */
278
+ public function getRateLimit()
279
+ {
280
+ return $this->_xRateLimitRemaining;
281
+ }
282
+
283
+ /**
284
+ * Modify the relationship between the current user and the target user.
285
+ *
286
+ * @param string $action Action command (follow/unfollow/approve/ignore)
287
+ * @param int $user Target user ID
288
+ *
289
+ * @return mixed
290
+ *
291
+ * @throws Exception
292
+ */
293
+ public function modifyRelationship($action, $user)
294
+ {
295
+ if (in_array($action, $this->_actions) && isset($user)) {
296
+ return $this->_makeCall('users/' . $user . '/relationship', array('action' => $action), 'POST');
297
+ }
298
+
299
+ throw new Exception('Error: modifyRelationship() | This method requires an action command and the target user id.');
300
+ }
301
+
302
+ /**
303
+ * Search media by its location.
304
+ *
305
+ * @param float $lat Latitude of the center search coordinate
306
+ * @param float $lng Longitude of the center search coordinate
307
+ * @param int $distance Distance in metres (default is 1km (distance=1000), max. is 5km)
308
+ *
309
+ * @return mixed
310
+ */
311
+ public function searchMedia($lat, $lng, $distance = 1000)
312
+ {
313
+ return $this->_makeCall('media/search', array(
314
+ 'lat' => $lat,
315
+ 'lng' => $lng,
316
+ 'distance' => $distance
317
+ ));
318
+ }
319
+
320
+ /**
321
+ * Get media by its id.
322
+ *
323
+ * @param int $id Instagram media ID
324
+ *
325
+ * @return mixed
326
+ */
327
+ public function getMedia($id)
328
+ {
329
+ return $this->_makeCall('media/' . $id);
330
+ }
331
+
332
+ /**
333
+ * Search for tags by name.
334
+ *
335
+ * @param string $name Valid tag name
336
+ *
337
+ * @return mixed
338
+ */
339
+ public function searchTags($name)
340
+ {
341
+ return $this->_makeCall('tags/search', array('q' => $name));
342
+ }
343
+
344
+ /**
345
+ * Get info about a tag
346
+ *
347
+ * @param string $name Valid tag name
348
+ *
349
+ * @return mixed
350
+ */
351
+ public function getTag($name)
352
+ {
353
+ return $this->_makeCall('tags/' . $name);
354
+ }
355
+
356
+ /**
357
+ * Get a recently tagged media.
358
+ *
359
+ * @param string $name Valid tag name
360
+ * @param int $limit Limit of returned results
361
+ * @param int $min_tag_id Return media before this min_tag_id
362
+ * @param int $max_tag_id Return media after this max_tag_id
363
+ *
364
+ * @return mixed
365
+ */
366
+ public function getTagMedia($name, $limit = 0, $min_tag_id = null, $max_tag_id = null)
367
+ {
368
+ $params = array();
369
+
370
+ if ($limit > 0) {
371
+ $params['count'] = $limit;
372
+ }
373
+ if ($min_tag_id !== null) {
374
+ $params['min_tag_id'] = $min_tag_id;
375
+ }
376
+ if ($max_tag_id !== null) {
377
+ $params['max_tag_id'] = $max_tag_id;
378
+ }
379
+
380
+ return $this->_makeCall('tags/' . $name . '/media/recent', $params);
381
+ }
382
+
383
+ /**
384
+ * Get a list of users who have liked this media.
385
+ *
386
+ * @param int $id Instagram media ID
387
+ *
388
+ * @return mixed
389
+ */
390
+ public function getMediaLikes($id)
391
+ {
392
+ return $this->_makeCall('media/' . $id . '/likes');
393
+ }
394
+
395
+ /**
396
+ * Get a list of comments for this media.
397
+ *
398
+ * @param int $id Instagram media ID
399
+ *
400
+ * @return mixed
401
+ */
402
+ public function getMediaComments($id)
403
+ {
404
+ return $this->_makeCall('media/' . $id . '/comments');
405
+ }
406
+
407
+ /**
408
+ * Add a comment on a media.
409
+ *
410
+ * @param int $id Instagram media ID
411
+ * @param string $text Comment content
412
+ *
413
+ * @return mixed
414
+ */
415
+ public function addMediaComment($id, $text)
416
+ {
417
+ return $this->_makeCall('media/' . $id . '/comments', array('text' => $text), 'POST');
418
+ }
419
+
420
+ /**
421
+ * Remove user comment on a media.
422
+ *
423
+ * @param int $id Instagram media ID
424
+ * @param string $commentID User comment ID
425
+ *
426
+ * @return mixed
427
+ */
428
+ public function deleteMediaComment($id, $commentID)
429
+ {
430
+ return $this->_makeCall('media/' . $id . '/comments/' . $commentID, null, 'DELETE');
431
+ }
432
+
433
+ /**
434
+ * Set user like on a media.
435
+ *
436
+ * @param int $id Instagram media ID
437
+ *
438
+ * @return mixed
439
+ */
440
+ public function likeMedia($id)
441
+ {
442
+ return $this->_makeCall('media/' . $id . '/likes', null, 'POST');
443
+ }
444
+
445
+ /**
446
+ * Remove user like on a media.
447
+ *
448
+ * @param int $id Instagram media ID
449
+ *
450
+ * @return mixed
451
+ */
452
+ public function deleteLikedMedia($id)
453
+ {
454
+ return $this->_makeCall('media/' . $id . '/likes', null, 'DELETE');
455
+ }
456
+
457
+ /**
458
+ * Get information about a location.
459
+ *
460
+ * @param int $id Instagram location ID
461
+ *
462
+ * @return mixed
463
+ */
464
+ public function getLocation($id)
465
+ {
466
+ return $this->_makeCall('locations/' . $id);
467
+ }
468
+
469
+ /**
470
+ * Get recent media from a given location.
471
+ *
472
+ * @param int $id Instagram location ID
473
+ * @param int $min_id Return media before this min_id
474
+ * @param int $max_id Return media after this max_id
475
+ *
476
+ * @return mixed
477
+ */
478
+ public function getLocationMedia($id, $min_id = null, $max_id = null)
479
+ {
480
+ $params = array();
481
+
482
+ if (isset($min_id)) {
483
+ $params['min_id'] = $min_id;
484
+ }
485
+ if (isset($max_id)) {
486
+ $params['max_id'] = $max_id;
487
+ }
488
+
489
+ return $this->_makeCall('locations/' . $id . '/media/recent', $params);
490
+ }
491
+
492
+ /**
493
+ * Get recent media from a given location.
494
+ *
495
+ * @param float $lat Latitude of the center search coordinate
496
+ * @param float $lng Longitude of the center search coordinate
497
+ * @param int $distance Distance in meter (max. distance: 5km = 5000)
498
+ * @param int $facebook_places_id Returns a location mapped off of a
499
+ * Facebook places id. If used, a Foursquare
500
+ * id and lat, lng are not required.
501
+ * @param int $foursquare_id Returns a location mapped off of a foursquare v2
502
+ * api location id. If used, you are not
503
+ * required to use lat and lng.
504
+ *
505
+ * @return mixed
506
+ */
507
+ public function searchLocation($lat, $lng, $distance = 1000, $facebook_places_id = null, $foursquare_id = null)
508
+ {
509
+ $params['lat'] = $lat;
510
+ $params['lng'] = $lng;
511
+ $params['distance'] = $distance;
512
+ if (isset($facebook_places_id)) {
513
+ $params['facebook_places_id'] = $facebook_places_id;
514
+ }
515
+ if (isset($foursquare_id)) {
516
+ $params['foursquare_id'] = $foursquare_id;
517
+ }
518
+
519
+ return $this->_makeCall('locations/search', $params);
520
+ }
521
+
522
+ /**
523
+ * Pagination feature.
524
+ *
525
+ * @param object $obj Instagram object returned by a method
526
+ * @param int $limit Limit of returned results
527
+ *
528
+ * @return mixed
529
+ *
530
+ * @throws Exception
531
+ */
532
+ public function pagination($obj, $limit = 0)
533
+ {
534
+ if (is_object($obj) && !is_null($obj->pagination)) {
535
+ if (!isset($obj->pagination->next_url)) {
536
+ return;
537
+ }
538
+
539
+ $apiCall = explode('?', $obj->pagination->next_url);
540
+
541
+ if (count($apiCall) < 2) {
542
+ return;
543
+ }
544
+
545
+ $function = str_replace(self::API_URL, '', $apiCall[0]);
546
+ $count = ($limit) ? $limit : count($obj->data);
547
+
548
+ if (isset($obj->pagination->next_max_tag_id)) {
549
+ return $this->_makeCall($function, array('max_tag_id' => $obj->pagination->next_max_tag_id, 'count' => $count));
550
+ }
551
+
552
+ return $this->_makeCall($function, array('next_max_id' => $obj->pagination->next_max_id, 'count' => $count));
553
+ }
554
+ throw new Exception("Error: pagination() | This method doesn't support pagination.");
555
+ }
556
+
557
+ /**
558
+ * Get the OAuth data of a user by the returned callback code.
559
+ *
560
+ * @param string $code OAuth2 code variable (after a successful login)
561
+ * @param bool $token If it's true, only the access token will be returned
562
+ *
563
+ * @return mixed
564
+ */
565
+ public function getOAuthToken($code, $token = false)
566
+ {
567
+ $apiData = array(
568
+ 'grant_type' => 'authorization_code',
569
+ 'client_id' => $this->getApiKey(),
570
+ 'client_secret' => $this->getApiSecret(),
571
+ 'redirect_uri' => $this->getApiCallback(),
572
+ 'code' => $code
573
+ );
574
+
575
+ $result = $this->_makeOAuthCall($apiData);
576
+
577
+ return !$token ? $result : $result->access_token;
578
+ }
579
+
580
+ /**
581
+ * The call operator.
582
+ *
583
+ * @param string $function API resource path
584
+ * @param array $params Additional request parameters
585
+ * @param string $method Request type GET|POST
586
+ *
587
+ * @return mixed
588
+ *
589
+ * @throws Exception
590
+ */
591
+ protected function _makeCall($function, $params = null, $method = 'GET')
592
+ {
593
+ if (!isset($this->_accesstoken)) {
594
+ throw new Exception("Error: _makeCall() | $function - This method requires an authenticated users access token.");
595
+ }
596
+
597
+ $authMethod = '?access_token=' . $this->getAccessToken();
598
+
599
+ $paramString = null;
600
+
601
+ if (isset($params) && is_array($params)) {
602
+ $paramString = '&' . http_build_query($params);
603
+ }
604
+
605
+ $apiCall = self::API_URL . $function . $authMethod . (('GET' === $method) ? $paramString : null);
606
+
607
+ // we want JSON
608
+ $headerData = array('Accept: application/json');
609
+
610
+ if ($this->_signedheader) {
611
+ $apiCall .= (strstr($apiCall, '?') ? '&' : '?') . 'sig=' . $this->_signHeader($function, $authMethod, $params);
612
+ }
613
+
614
+ $ch = curl_init();
615
+ curl_setopt($ch, CURLOPT_URL, $apiCall);
616
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $headerData);
617
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
618
+ curl_setopt($ch, CURLOPT_TIMEOUT, 90);
619
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
620
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
621
+ curl_setopt($ch, CURLOPT_HEADER, true);
622
+
623
+ switch ($method) {
624
+ case 'POST':
625
+ curl_setopt($ch, CURLOPT_POST, count($params));
626
+ curl_setopt($ch, CURLOPT_POSTFIELDS, ltrim($paramString, '&'));
627
+ break;
628
+ case 'DELETE':
629
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
630
+ break;
631
+ }
632
+
633
+ $jsonData = curl_exec($ch);
634
+ // split header from JSON data
635
+ // and assign each to a variable
636
+ list($headerContent, $jsonData) = explode("\r\n\r\n", $jsonData, 2);
637
+
638
+ // convert header content into an array
639
+ $headers = $this->processHeaders($headerContent);
640
+
641
+ // get the 'X-Ratelimit-Remaining' header value
642
+ if (isset($headers['X-Ratelimit-Remaining'])) {
643
+ $this->_xRateLimitRemaining = trim($headers['X-Ratelimit-Remaining']);
644
+ }
645
+
646
+ if (!$jsonData) {
647
+ throw new Exception('Error: _makeCall() - cURL error: ' . curl_error($ch));
648
+ }
649
+
650
+ curl_close($ch);
651
+
652
+ return json_decode($jsonData);
653
+ }
654
+
655
+ /**
656
+ * The OAuth call operator.
657
+ *
658
+ * @param array $apiData The post API data
659
+ *
660
+ * @return mixed
661
+ *
662
+ * @throws Exception
663
+ */
664
+ private function _makeOAuthCall($apiData)
665
+ {
666
+ $apiHost = self::API_OAUTH_TOKEN_URL;
667
+
668
+ $ch = curl_init();
669
+ curl_setopt($ch, CURLOPT_URL, $apiHost);
670
+ curl_setopt($ch, CURLOPT_POST, count($apiData));
671
+ curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($apiData));
672
+ curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json'));
673
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
674
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
675
+ curl_setopt($ch, CURLOPT_TIMEOUT, 90);
676
+ $jsonData = curl_exec($ch);
677
+
678
+ if (!$jsonData) {
679
+ throw new Exception('Error: _makeOAuthCall() - cURL error: ' . curl_error($ch));
680
+ }
681
+
682
+ curl_close($ch);
683
+
684
+ return json_decode($jsonData);
685
+ }
686
+
687
+ /**
688
+ * Sign header by using endpoint, parameters and the API secret.
689
+ *
690
+ * @param string
691
+ * @param string
692
+ * @param array
693
+ *
694
+ * @return string The signature
695
+ */
696
+ private function _signHeader($endpoint, $authMethod, $params)
697
+ {
698
+ if (!is_array($params)) {
699
+ $params = array();
700
+ }
701
+ if ($authMethod) {
702
+ list($key, $value) = explode('=', substr($authMethod, 1), 2);
703
+ $params[$key] = $value;
704
+ }
705
+ $baseString = '/' . $endpoint;
706
+ ksort($params);
707
+ foreach ($params as $key => $value) {
708
+ $baseString .= '|' . $key . '=' . $value;
709
+ }
710
+ $signature = hash_hmac('sha256', $baseString, $this->_apisecret, false);
711
+
712
+ return $signature;
713
+ }
714
+
715
+ /**
716
+ * Read and process response header content.
717
+ *
718
+ * @param array
719
+ *
720
+ * @return array
721
+ */
722
+ private function processHeaders($headerContent)
723
+ {
724
+ $headers = array();
725
+
726
+ foreach (explode("\r\n", $headerContent) as $i => $line) {
727
+ if ($i === 0) {
728
+ $headers['http_code'] = $line;
729
+ continue;
730
+ }
731
+
732
+ list($key, $value) = explode(':', $line);
733
+ $headers[$key] = $value;
734
+ }
735
+
736
+ return $headers;
737
+ }
738
+
739
+ /**
740
+ * Access Token Setter.
741
+ *
742
+ * @param object|string $data
743
+ *
744
+ * @return void
745
+ */
746
+ public function setAccessToken($data)
747
+ {
748
+ $token = is_object($data) ? $data->access_token : $data;
749
+
750
+ $this->_accesstoken = $token;
751
+ }
752
+
753
+ /**
754
+ * Access Token Getter.
755
+ *
756
+ * @return string
757
+ */
758
+ public function getAccessToken()
759
+ {
760
+ return $this->_accesstoken;
761
+ }
762
+
763
+ /**
764
+ * API-key Setter
765
+ *
766
+ * @param string $apiKey
767
+ *
768
+ * @return void
769
+ */
770
+ public function setApiKey($apiKey)
771
+ {
772
+ $this->_apikey = $apiKey;
773
+ }
774
+
775
+ /**
776
+ * API Key Getter
777
+ *
778
+ * @return string
779
+ */
780
+ public function getApiKey()
781
+ {
782
+ return $this->_apikey;
783
+ }
784
+
785
+ /**
786
+ * API Secret Setter
787
+ *
788
+ * @param string $apiSecret
789
+ *
790
+ * @return void
791
+ */
792
+ public function setApiSecret($apiSecret)
793
+ {
794
+ $this->_apisecret = $apiSecret;
795
+ }
796
+
797
+ /**
798
+ * API Secret Getter.
799
+ *
800
+ * @return string
801
+ */
802
+ public function getApiSecret()
803
+ {
804
+ return $this->_apisecret;
805
+ }
806
+
807
+ /**
808
+ * API Callback URL Setter.
809
+ *
810
+ * @param string $apiCallback
811
+ *
812
+ * @return void
813
+ */
814
+ public function setApiCallback($apiCallback)
815
+ {
816
+ $this->_callbackurl = $apiCallback;
817
+ }
818
+
819
+ /**
820
+ * API Callback URL Getter.
821
+ *
822
+ * @return string
823
+ */
824
+ public function getApiCallback()
825
+ {
826
+ return $this->_callbackurl;
827
+ }
828
+
829
+ /**
830
+ * Enforce Signed Header.
831
+ *
832
+ * @param bool $signedHeader
833
+ *
834
+ * @return void
835
+ */
836
+ public function setSignedHeader($signedHeader)
837
+ {
838
+ $this->_signedheader = $signedHeader;
839
+ }
840
  }
app/code/community/Neklo/Instagram/Model/Source/Mode.php ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Neklo_Instagram_Model_Source_Mode
4
+ {
5
+ const BY_USER_ID_CODE = 1;
6
+ const BY_USER_ID_LABEL = 'By User ID';
7
+
8
+ const BY_HASHTAG_CODE = 2;
9
+ const BY_HASHTAG_LABEL = 'By Hashtag';
10
+
11
+ const BY_PRODUCT_HASHTAG_CODE = 3;
12
+ const BY_PRODUCT_HASHTAG_LABEL = 'By Product Hashtag';
13
+
14
+ const BY_USER_NAME_CODE = 4;
15
+ const BY_USER_NAME_LABEL = 'By User Name';
16
+
17
+ /**
18
+ * Options getter
19
+ *
20
+ * @return array
21
+ */
22
+ public function toOptionArray()
23
+ {
24
+ $helper = Mage::helper('neklo_instagram');
25
+ return array(
26
+ array(
27
+ 'value' => self::BY_USER_NAME_CODE,
28
+ 'label' => $helper->__(self::BY_USER_NAME_LABEL)
29
+ ),
30
+ array(
31
+ 'value' => self::BY_USER_ID_CODE,
32
+ 'label' => $helper->__(self::BY_USER_ID_LABEL)
33
+ ),
34
+ array(
35
+ 'value' => self::BY_PRODUCT_HASHTAG_CODE,
36
+ 'label' => $helper->__(self::BY_PRODUCT_HASHTAG_LABEL)
37
+ ),
38
+ array(
39
+ 'value' => self::BY_HASHTAG_CODE,
40
+ 'label' => $helper->__(self::BY_HASHTAG_LABEL)
41
+ ),
42
+ );
43
+ }
44
+
45
+ /**
46
+ * Get options in "key-value" format
47
+ *
48
+ * @return array
49
+ */
50
+ public function toArray()
51
+ {
52
+ $helper = Mage::helper('neklo_instagram');
53
+ return array(
54
+ self::BY_USER_NAME_CODE => $helper->__(self::BY_USER_NAME_LABEL),
55
+ self::BY_USER_ID_CODE => $helper->__(self::BY_USER_ID_LABEL),
56
+ self::BY_PRODUCT_HASHTAG_CODE => $helper->__(self::BY_PRODUCT_HASHTAG_LABEL),
57
+ self::BY_HASHTAG_CODE => $helper->__(self::BY_HASHTAG_LABEL),
58
+ );
59
+ }
60
+ }
app/code/community/Neklo/Instagram/Model/System/Config/Backend/Empty.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Neklo_Instagram_Model_System_Config_Backend_Empty extends Mage_Core_Model_Config_Data
4
+ {
5
+ public function getValue()
6
+ {
7
+ return null;
8
+ }
9
+ }
app/code/community/Neklo/Instagram/controllers/Adminhtml/Neklo/Instagram/ApiController.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Neklo_Instagram_Adminhtml_Neklo_Instagram_ApiController extends Mage_Adminhtml_Controller_Action
4
+ {
5
+ protected $_api = null;
6
+
7
+ public function connectAction()
8
+ {
9
+ $code = $this->getRequest()->getParam('code', null);
10
+ if ($code === null) {
11
+ $this->_getConfig()->disconnect();
12
+ $this->loadLayout();
13
+ $this->renderLayout();
14
+ $this->_getSession()->addError(Mage::helper('neklo_instagram')->__('Incorrect Instagram authorization code.'));
15
+ return $this;
16
+ }
17
+ try {
18
+ $accessToken = $this->_getApi()->getOAuthToken($code, true);
19
+ } catch (Exception $e) {
20
+ $this->_getConfig()->disconnect();
21
+ $this->loadLayout();
22
+ $this->renderLayout();
23
+ $this->_getSession()->addError(Mage::helper('neklo_instagram')->__($e->getMessage()));
24
+ return $this;
25
+ }
26
+
27
+ if (!$accessToken) {
28
+ $this->_getConfig()->disconnect();
29
+ $this->loadLayout();
30
+ $this->renderLayout();
31
+ $this->_getSession()->addError(Mage::helper('neklo_instagram')->__('Incorrect Instagram authorization code.'));
32
+ return $this;
33
+ }
34
+
35
+ $this->_getConfig()->connect($accessToken);
36
+ $this->loadLayout();
37
+ $this->renderLayout();
38
+ $this->_getSession()->addSuccess(Mage::helper('neklo_instagram')->__('Instagram connect is successful.'));
39
+ return $this;
40
+ }
41
+
42
+ public function disconnectAction()
43
+ {
44
+ $this->_getConfig()->disconnect();
45
+ $this->_getSession()->addSuccess(Mage::helper('neklo_instagram')->__('Instagram disconnect is successful.'));
46
+ return $this->_redirect('adminhtml/system_config/edit', array('section' => 'neklo_instagram'));
47
+ }
48
+
49
+ public function getRedirectUrl()
50
+ {
51
+ return Mage::helper("adminhtml")->getUrl("adminhtml/neklo_instagram_api/connect");
52
+ }
53
+
54
+ /**
55
+ * @return Neklo_Instagram_Model_Instagram_Api
56
+ */
57
+ protected function _getApi()
58
+ {
59
+ if ($this->_api === null) {
60
+ $this->_api = $this->_api = Mage::getModel(
61
+ 'neklo_instagram/instagram_api',
62
+ array(
63
+ 'apiKey' => $this->_getConfig()->getClientId(),
64
+ 'apiSecret' => $this->_getConfig()->getClientSecret(),
65
+ 'apiCallback' => $this->getRedirectUrl(),
66
+ )
67
+ );
68
+ }
69
+ return $this->_api;
70
+ }
71
+
72
+ /**
73
+ * @return Neklo_Instagram_Helper_Config
74
+ */
75
+ protected function _getConfig()
76
+ {
77
+ return Mage::helper('neklo_instagram/config');
78
+ }
79
+
80
+ protected function _isAllowed()
81
+ {
82
+ return Mage::getSingleton('admin/session')->isAllowed('system/config/neklo_instagram');
83
+ }
84
+ }
app/code/community/Neklo/Instagram/etc/adminhtml.xml CHANGED
@@ -1,23 +1,23 @@
1
- <?xml version="1.0"?>
2
- <config>
3
- <acl>
4
- <resources>
5
- <admin>
6
- <children>
7
- <system>
8
- <children>
9
- <config>
10
- <children>
11
- <neklo_instagram translate="title" module="neklo_instagram">
12
- <title>Neklo Instagram Widget</title>
13
- <sort_order>9998</sort_order>
14
- </neklo_instagram>
15
- </children>
16
- </config>
17
- </children>
18
- </system>
19
- </children>
20
- </admin>
21
- </resources>
22
- </acl>
23
  </config>
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <acl>
4
+ <resources>
5
+ <admin>
6
+ <children>
7
+ <system>
8
+ <children>
9
+ <config>
10
+ <children>
11
+ <neklo_instagram translate="title" module="neklo_instagram">
12
+ <title>Neklo Instagram Widget</title>
13
+ <sort_order>9998</sort_order>
14
+ </neklo_instagram>
15
+ </children>
16
+ </config>
17
+ </children>
18
+ </system>
19
+ </children>
20
+ </admin>
21
+ </resources>
22
+ </acl>
23
  </config>
app/code/community/Neklo/Instagram/etc/config.xml CHANGED
@@ -1,62 +1,83 @@
1
- <?xml version="1.0"?>
2
- <config>
3
- <modules>
4
- <Neklo_Instagram>
5
- <version>1.0.3</version>
6
- </Neklo_Instagram>
7
- </modules>
8
- <frontend>
9
- <layout>
10
- <updates>
11
- <neklo_instagram>
12
- <file>neklo_instagram.xml</file>
13
- </neklo_instagram>
14
- </updates>
15
- </layout>
16
- </frontend>
17
- <adminhtml>
18
- <translate>
19
- <modules>
20
- <Neklo_Instagram>
21
- <files>
22
- <default>Neklo_Instagram.csv</default>
23
- </files>
24
- </Neklo_Instagram>
25
- </modules>
26
- </translate>
27
- </adminhtml>
28
- <global>
29
- <blocks>
30
- <neklo_instagram>
31
- <class>Neklo_Instagram_Block</class>
32
- </neklo_instagram>
33
- </blocks>
34
- <helpers>
35
- <neklo_instagram>
36
- <class>Neklo_Instagram_Helper</class>
37
- </neklo_instagram>
38
- </helpers>
39
- <models>
40
- <neklo_instagram>
41
- <class>Neklo_Instagram_Model</class>
42
- </neklo_instagram>
43
- </models>
44
- <resources>
45
- <neklo_instagram_setup>
46
- <setup>
47
- <module>Neklo_Instagram</module>
48
- </setup>
49
- <connection>
50
- <use>core_setup</use>
51
- </connection>
52
- </neklo_instagram_setup>
53
- </resources>
54
- </global>
55
- <default>
56
- <neklo_instagram>
57
- <general>
58
- <cache_lifetime>3600</cache_lifetime>
59
- </general>
60
- </neklo_instagram>
61
- </default>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  </config>
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Neklo_Instagram>
5
+ <version>1.1.0</version>
6
+ </Neklo_Instagram>
7
+ </modules>
8
+ <admin>
9
+ <routers>
10
+ <adminhtml>
11
+ <args>
12
+ <modules>
13
+ <Neklo_Instagram before="Mage_Adminhtml">Neklo_Instagram_Adminhtml</Neklo_Instagram>
14
+ </modules>
15
+ </args>
16
+ </adminhtml>
17
+ </routers>
18
+ </admin>
19
+ <frontend>
20
+ <layout>
21
+ <updates>
22
+ <neklo_instagram>
23
+ <file>neklo_instagram.xml</file>
24
+ </neklo_instagram>
25
+ </updates>
26
+ </layout>
27
+ </frontend>
28
+ <adminhtml>
29
+ <layout>
30
+ <updates>
31
+ <neklo_instagram>
32
+ <file>neklo/instagram.xml</file>
33
+ </neklo_instagram>
34
+ </updates>
35
+ </layout>
36
+ <translate>
37
+ <modules>
38
+ <Neklo_Instagram>
39
+ <files>
40
+ <default>Neklo_Instagram.csv</default>
41
+ </files>
42
+ </Neklo_Instagram>
43
+ </modules>
44
+ </translate>
45
+ </adminhtml>
46
+ <global>
47
+ <blocks>
48
+ <neklo_instagram>
49
+ <class>Neklo_Instagram_Block</class>
50
+ </neklo_instagram>
51
+ <neklo_instagram_adminhtml>
52
+ <class>Neklo_Instagram_Block_Adminhtml</class>
53
+ </neklo_instagram_adminhtml>
54
+ </blocks>
55
+ <helpers>
56
+ <neklo_instagram>
57
+ <class>Neklo_Instagram_Helper</class>
58
+ </neklo_instagram>
59
+ </helpers>
60
+ <models>
61
+ <neklo_instagram>
62
+ <class>Neklo_Instagram_Model</class>
63
+ </neklo_instagram>
64
+ </models>
65
+ <resources>
66
+ <neklo_instagram_setup>
67
+ <setup>
68
+ <module>Neklo_Instagram</module>
69
+ </setup>
70
+ <connection>
71
+ <use>core_setup</use>
72
+ </connection>
73
+ </neklo_instagram_setup>
74
+ </resources>
75
+ </global>
76
+ <default>
77
+ <neklo_instagram>
78
+ <general>
79
+ <cache_lifetime>3600</cache_lifetime>
80
+ </general>
81
+ </neklo_instagram>
82
+ </default>
83
  </config>
app/code/community/Neklo/Instagram/etc/system.xml CHANGED
@@ -1,36 +1,86 @@
1
- <?xml version="1.0"?>
2
- <config>
3
- <sections>
4
- <neklo_instagram module="neklo_instagram">
5
- <label>Instagram Widget</label>
6
- <tab>neklo</tab>
7
- <frontend_type>text</frontend_type>
8
- <sort_order>200</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>10</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
- <cache_lifetime translate="label comment">
22
- <label>Cache Lifetime</label>
23
- <frontend_type>text</frontend_type>
24
- <sort_order>20</sort_order>
25
- <show_in_default>1</show_in_default>
26
- <show_in_website>1</show_in_website>
27
- <show_in_store>1</show_in_store>
28
- <validate>validate-zero-or-greater</validate>
29
- <comment>In seconds</comment>
30
- </cache_lifetime>
31
- </fields>
32
- </general>
33
- </groups>
34
- </neklo_instagram>
35
- </sections>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  </config>
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <sections>
4
+ <neklo_instagram module="neklo_instagram">
5
+ <label>Instagram Widget</label>
6
+ <tab>neklo</tab>
7
+ <frontend_type>text</frontend_type>
8
+ <sort_order>200</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 Settings</label>
15
+ <frontend_type>text</frontend_type>
16
+ <sort_order>10</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
+ <cache_lifetime translate="label comment">
22
+ <label>Cache Lifetime</label>
23
+ <frontend_type>text</frontend_type>
24
+ <sort_order>10</sort_order>
25
+ <show_in_default>1</show_in_default>
26
+ <show_in_website>1</show_in_website>
27
+ <show_in_store>1</show_in_store>
28
+ <validate>validate-zero-or-greater</validate>
29
+ <comment>In seconds</comment>
30
+ </cache_lifetime>
31
+ </fields>
32
+ </general>
33
+ <api translate="label">
34
+ <label>API Settings</label>
35
+ <frontend_type>text</frontend_type>
36
+ <sort_order>20</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
+ <fields>
41
+ <status translate="label">
42
+ <label>Status</label>
43
+ <frontend_type>label</frontend_type>
44
+ <frontend_model>neklo_instagram_adminhtml/system_config_frontend_status</frontend_model>
45
+ <backend_model>neklo_instagram/system_config_backend_empty</backend_model>
46
+ <sort_order>10</sort_order>
47
+ <show_in_default>1</show_in_default>
48
+ <show_in_website>0</show_in_website>
49
+ <show_in_store>0</show_in_store>
50
+ </status>
51
+ <client_id translate="label comment">
52
+ <label>Client ID</label>
53
+ <frontend_type>text</frontend_type>
54
+ <sort_order>20</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
+ <depends>
59
+ <status>0</status>
60
+ </depends>
61
+ </client_id>
62
+ <client_secret translate="label comment">
63
+ <label>Client Secret</label>
64
+ <frontend_type>text</frontend_type>
65
+ <sort_order>30</sort_order>
66
+ <show_in_default>1</show_in_default>
67
+ <show_in_website>1</show_in_website>
68
+ <show_in_store>1</show_in_store>
69
+ <depends>
70
+ <status>0</status>
71
+ </depends>
72
+ </client_secret>
73
+ <oauth>
74
+ <frontend_model>neklo_instagram_adminhtml/system_config_frontend_oauth</frontend_model>
75
+ <sort_order>40</sort_order>
76
+ <show_in_default>1</show_in_default>
77
+ <show_in_website>0</show_in_website>
78
+ <show_in_store>0</show_in_store>
79
+ <comment>{{connect_hint}}</comment>
80
+ </oauth>
81
+ </fields>
82
+ </api>
83
+ </groups>
84
+ </neklo_instagram>
85
+ </sections>
86
  </config>
app/code/community/Neklo/Instagram/etc/widget.xml CHANGED
@@ -1,110 +1,122 @@
1
- <?xml version="1.0"?>
2
- <widgets>
3
- <neklo_instagram type="neklo_instagram/widget_feed" module="neklo_instagram">
4
- <name>Neklo Instagram Widget</name>
5
- <parameters>
6
- <mode translate="label">
7
- <label>Mode</label>
8
- <type>select</type>
9
- <visible>1</visible>
10
- <sort_order>10</sort_order>
11
- <values>
12
- <use_user_id translate="label">
13
- <value>1</value>
14
- <label>By User ID</label>
15
- </use_user_id>
16
- <use_hashtag translate="label">
17
- <value>2</value>
18
- <label>By Hashtag</label>
19
- </use_hashtag>
20
- <use_product_hashtag translate="label">
21
- <value>3</value>
22
- <label>By Product Hashtag</label>
23
- </use_product_hashtag>
24
- </values>
25
- <value>1</value>
26
- </mode>
27
-
28
- <user_id translate="label description">
29
- <label>User ID</label>
30
- <required>0</required>
31
- <visible>1</visible>
32
- <type>text</type>
33
- <value></value>
34
- <sort_order>20</sort_order>
35
- <description>{how-to-get-user-id}</description>
36
- <depends><mode><value>1</value></mode></depends>
37
- </user_id>
38
-
39
- <hashtag translate="label">
40
- <label>Hashtag</label>
41
- <required>0</required>
42
- <visible>1</visible>
43
- <type>text</type>
44
- <value></value>
45
- <sort_order>30</sort_order>
46
- <depends><mode><value>2</value></mode></depends>
47
- </hashtag>
48
-
49
- <title translate="label description">
50
- <label>Title</label>
51
- <required>0</required>
52
- <visible>1</visible>
53
- <type>text</type>
54
- <value></value>
55
- <sort_order>40</sort_order>
56
- <description>Example: Instagram Feed #%s </description>
57
- </title>
58
-
59
- <description translate="label description">
60
- <label>Description</label>
61
- <required>0</required>
62
- <visible>1</visible>
63
- <type>textarea</type>
64
- <value></value>
65
- <sort_order>50</sort_order>
66
- <description>Example: Description for feed #%s </description>
67
- </description>
68
-
69
- <limit_items translate="label">
70
- <label>Limit</label>
71
- <required>1</required>
72
- <visible>1</visible>
73
- <type>text</type>
74
- <value>5</value>
75
- <sort_order>60</sort_order>
76
- </limit_items>
77
-
78
- <image_width translate="label">
79
- <label>Thumbnail Width</label>
80
- <required>1</required>
81
- <visible>1</visible>
82
- <type>text</type>
83
- <value>200</value>
84
- <sort_order>70</sort_order>
85
- </image_width>
86
- <image_height translate="label">
87
- <label>Thumbnail Height</label>
88
- <required>1</required>
89
- <visible>1</visible>
90
- <type>text</type>
91
- <value>200</value>
92
- <sort_order>80</sort_order>
93
- </image_height>
94
-
95
- <template translate="label">
96
- <label>Template</label>
97
- <visible>1</visible>
98
- <type>select</type>
99
- <value>neklo_instagram/widget/feed.phtml</value>
100
- <values>
101
- <featured translate="label">
102
- <value>neklo_instagram/widget/feed.phtml</value>
103
- <label>Neklo Instagram Template</label>
104
- </featured>
105
- </values>
106
- <sort_order>90</sort_order>
107
- </template>
108
- </parameters>
109
- </neklo_instagram>
 
 
 
 
 
 
 
 
 
 
 
 
110
  </widgets>
1
+ <?xml version="1.0"?>
2
+ <widgets>
3
+ <neklo_instagram type="neklo_instagram/widget_feed" module="neklo_instagram">
4
+ <name>[NEKLO] Instagram Widget</name>
5
+ <parameters>
6
+ <is_enabled translate="label">
7
+ <label>Is Enabled</label>
8
+ <required>1</required>
9
+ <visible>1</visible>
10
+ <sort_order>10</sort_order>
11
+ <type>select</type>
12
+ <source_model>adminhtml/system_config_source_yesno</source_model>
13
+ <value>1</value>
14
+ </is_enabled>
15
+ <mode translate="label">
16
+ <label>Mode</label>
17
+ <required>1</required>
18
+ <visible>1</visible>
19
+ <sort_order>20</sort_order>
20
+ <type>select</type>
21
+ <source_model>neklo_instagram/source_mode</source_model>
22
+ <value>4</value>
23
+ </mode>
24
+ <user_id translate="label description">
25
+ <label>User ID</label>
26
+ <required>1</required>
27
+ <visible>1</visible>
28
+ <sort_order>30</sort_order>
29
+ <type>text</type>
30
+ <value></value>
31
+ <description>{how-to-get-user-id}</description>
32
+ <depends>
33
+ <mode>
34
+ <value>1</value>
35
+ </mode>
36
+ </depends>
37
+ </user_id>
38
+ <hashtag translate="label">
39
+ <label>Hashtag</label>
40
+ <required>1</required>
41
+ <visible>1</visible>
42
+ <sort_order>40</sort_order>
43
+ <type>text</type>
44
+ <value></value>
45
+ <depends>
46
+ <mode>
47
+ <value>2</value>
48
+ </mode>
49
+ </depends>
50
+ </hashtag>
51
+ <user_name translate="label description">
52
+ <label>User Name</label>
53
+ <required>1</required>
54
+ <visible>1</visible>
55
+ <sort_order>50</sort_order>
56
+ <type>text</type>
57
+ <value></value>
58
+ <description><![CDATA[Example: http://instagram.com/<b>neklo_llc</b>]]></description>
59
+ <depends>
60
+ <mode>
61
+ <value>4</value>
62
+ </mode>
63
+ </depends>
64
+ </user_name>
65
+ <title translate="label description">
66
+ <label>Title</label>
67
+ <required>0</required>
68
+ <visible>1</visible>
69
+ <sort_order>60</sort_order>
70
+ <type>text</type>
71
+ <value></value>
72
+ <description><![CDATA[Example: Instagram Feed #%s<br/><b>%s</b> - replaces by hashtag]]></description>
73
+ </title>
74
+ <description translate="label description">
75
+ <label>Description</label>
76
+ <required>0</required>
77
+ <visible>1</visible>
78
+ <sort_order>70</sort_order>
79
+ <type>textarea</type>
80
+ <value></value>
81
+ <description><![CDATA[Example: Description Feed #%s<br/><b>%s</b> - replaces by hashtag]]></description>
82
+ </description>
83
+ <limit_items translate="label">
84
+ <label>Limit</label>
85
+ <required>1</required>
86
+ <visible>1</visible>
87
+ <sort_order>80</sort_order>
88
+ <type>text</type>
89
+ <value>5</value>
90
+ </limit_items>
91
+ <image_width translate="label">
92
+ <label>Thumbnail Width</label>
93
+ <required>1</required>
94
+ <visible>1</visible>
95
+ <sort_order>90</sort_order>
96
+ <type>text</type>
97
+ <value>200</value>
98
+ </image_width>
99
+ <image_height translate="label">
100
+ <label>Thumbnail Height</label>
101
+ <required>1</required>
102
+ <visible>1</visible>
103
+ <sort_order>100</sort_order>
104
+ <type>text</type>
105
+ <value>200</value>
106
+ </image_height>
107
+ <template translate="label">
108
+ <label>Template</label>
109
+ <visible>1</visible>
110
+ <type>select</type>
111
+ <value>neklo_instagram/widget/feed.phtml</value>
112
+ <values>
113
+ <featured translate="label">
114
+ <value>neklo_instagram/widget/feed.phtml</value>
115
+ <label>Instagram Widget Default Template</label>
116
+ </featured>
117
+ </values>
118
+ <sort_order>110</sort_order>
119
+ </template>
120
+ </parameters>
121
+ </neklo_instagram>
122
  </widgets>
app/code/community/Neklo/Instagram/sql/neklo_instagram_setup/mysql4-install-1.0.0.php CHANGED
@@ -1,35 +1,33 @@
1
- <?php
2
- $this->startSetup();
3
-
4
- $instagramHashtagAttr = Mage::getModel('catalog/product')->getResource()->getAttribute('instagram_hashtag');
5
-
6
- if (!$instagramHashtagAttr || !$instagramHashtagAttr->getId()) {
7
- Mage::getResourceModel('catalog/setup', 'catalog_setup')->addAttribute(
8
- Mage_Catalog_Model_Product::ENTITY, 'instagram_hashtag',
9
- array(
10
- 'group' => 'General',
11
- 'type' => 'varchar',
12
- 'backend' => '',
13
- 'frontend' => '',
14
- 'label' => 'Instagram Hashtag: #',
15
- 'input' => 'text',
16
- 'class' => '',
17
- 'source' => '',
18
- 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
19
- 'visible' => true,
20
- 'required' => false,
21
- 'user_defined' => true,
22
- 'default' => '',
23
- 'searchable' => true,
24
- 'filterable' => false,
25
- 'comparable' => false,
26
- 'visible_on_front' => false,
27
- 'unique' => false,
28
- 'apply_to' => '',
29
- 'is_configurable' => false,
30
- 'visible_on_front' => false,
31
- )
32
- );
33
- }
34
-
35
  $this->endSetup();
1
+ <?php
2
+ $this->startSetup();
3
+
4
+ $instagramHashtagAttr = Mage::getModel('catalog/product')->getResource()->getAttribute('instagram_hashtag');
5
+ if (!$instagramHashtagAttr || !$instagramHashtagAttr->getId()) {
6
+ Mage::getResourceModel('catalog/setup', 'catalog_setup')->addAttribute(
7
+ Mage_Catalog_Model_Product::ENTITY, 'instagram_hashtag',
8
+ array(
9
+ 'group' => 'General',
10
+ 'type' => 'varchar',
11
+ 'backend' => '',
12
+ 'frontend' => '',
13
+ 'label' => 'Instagram Hashtag: #',
14
+ 'input' => 'text',
15
+ 'class' => '',
16
+ 'source' => '',
17
+ 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
18
+ 'visible' => true,
19
+ 'required' => false,
20
+ 'user_defined' => true,
21
+ 'default' => '',
22
+ 'searchable' => true,
23
+ 'filterable' => false,
24
+ 'comparable' => false,
25
+ 'visible_on_front' => false,
26
+ 'unique' => false,
27
+ 'apply_to' => '',
28
+ 'is_configurable' => false,
29
+ )
30
+ );
31
+ }
32
+
 
 
33
  $this->endSetup();
app/design/adminhtml/default/default/layout/neklo/core.xml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <layout>
3
+ <adminhtml_system_config_edit>
4
+ <reference name="head">
5
+ <action method="addCss">
6
+ <name>neklo/core/css/style.css</name>
7
+ </action>
8
+ </reference>
9
+ </adminhtml_system_config_edit>
10
+ </layout>
app/design/adminhtml/default/default/layout/neklo/instagram.xml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <layout version="1.0.0">
3
+ <adminhtml_neklo_instagram_api_connect>
4
+ <reference name="root">
5
+ <action method="setTemplate">
6
+ <template>neklo/instagram/reload.phtml</template>
7
+ </action>
8
+ </reference>
9
+ </adminhtml_neklo_instagram_api_connect>
10
+ </layout>
app/design/adminhtml/default/default/template/neklo/core/system/contact/button.phtml ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php /* @var $this Neklo_Core_Block_System_Contact_Send_Button */ ?>
2
+ <?php echo $this->getButtonHtml(); ?>
3
+ <div class="neklo_core_message contact"></div>
4
+ <script>
5
+ var NekloCoreContact = Class.create({
6
+ initialize: function (config) {
7
+ this.initConfig(config);
8
+ this.initElements();
9
+ this.initObservers();
10
+ },
11
+
12
+ initConfig: function (config) {
13
+ this.config = config;
14
+ this.sendUrl = this.config.sendUrl || '';
15
+
16
+ this.successMessage = this.config.successMessage || '';
17
+ this.errorMessage = this.config.errorMessage || '';
18
+
19
+ this.successMessageClass = this.config.successMessageClass || '';
20
+ this.errorMessageClass = this.config.errorMessageClass || '';
21
+
22
+
23
+ this.formContainerId = this.config.formContainerId || '';
24
+ this.formElementSelectorList = this.config.formElementSelectorList || [];
25
+ },
26
+
27
+ initElements: function () {
28
+ this.sendButton = $(this.config.sendButtonId) || null;
29
+ this.loadingMask = $(this.config.loadingMaskId) || null;
30
+ this.messageContainer = $$(this.config.messageContainerSelector).first() || null;
31
+ },
32
+
33
+ initObservers: function () {
34
+ if (this.sendButton) {
35
+ this.sendButton.observe('click', this.send.bind(this));
36
+ }
37
+ },
38
+
39
+ send: function () {
40
+ if (!this.sendUrl) {
41
+ return;
42
+ }
43
+ if (!this.validate()) {
44
+ return;
45
+ }
46
+
47
+ var me = this;
48
+ var sendData = {};
49
+ $H(this.formElementSelectorList).map().each(function(elementSelector) {
50
+ if (Validation.isVisible($(me.formContainerId + '_' + elementSelector.key))) {
51
+ sendData[elementSelector.key] = $(me.formContainerId + '_' + elementSelector.key).getValue();
52
+ }
53
+ });
54
+
55
+ new Ajax.Request(
56
+ this.sendUrl,
57
+ {
58
+ method: 'post',
59
+ parameters: sendData,
60
+ onCreate: this._onSendCreate.bind(this),
61
+ onComplete: this._onSendComplete.bind(this),
62
+ onSuccess: this._onSendSuccess.bind(this),
63
+ onFailure: this._onSendFailure.bind(this)
64
+ }
65
+ );
66
+ },
67
+
68
+ validate: function () {
69
+ var me = this;
70
+ var result = true;
71
+ $H(this.formElementSelectorList).map().each(function(elementSelector) {
72
+ var element = $(me.formContainerId + '_' + elementSelector.key);
73
+ elementSelector.value.each(function(className) {
74
+ element.addClassName(className);
75
+ });
76
+ result = Validation.validate($(me.formContainerId + '_' + elementSelector.key)) && result;
77
+ elementSelector.value.each(function(className) {
78
+ element.removeClassName(className);
79
+ });
80
+ });
81
+ return result;
82
+ },
83
+
84
+ showLoadingMask: function () {
85
+ if (this.loadingMask) {
86
+ this.loadingMask.show();
87
+ }
88
+ },
89
+
90
+ hideLoadingMask: function () {
91
+ if (this.loadingMask) {
92
+ this.loadingMask.hide();
93
+ }
94
+ },
95
+
96
+ _onSendCreate: function () {
97
+ this.clearMessageContainer();
98
+ this.showLoadingMask();
99
+ },
100
+
101
+ _onSendComplete: function () {
102
+ this.hideLoadingMask();
103
+ },
104
+
105
+ _onSendSuccess: function (response) {
106
+ try {
107
+ var result = response.responseText.evalJSON();
108
+ if (typeof(result.success) != 'undefined') {
109
+ if (result.success) {
110
+ this.showSuccess();
111
+ this.clearForm();
112
+ } else {
113
+ this.showError();
114
+ }
115
+ }
116
+ } catch (e) {
117
+ this.showError();
118
+ }
119
+ },
120
+
121
+ _onSendFailure: function () {
122
+ this.showError();
123
+ },
124
+
125
+ showSuccess: function () {
126
+ this.showMessage(this.successMessage, this.successMessageClass);
127
+ },
128
+
129
+ showError: function () {
130
+ this.showMessage(this.errorMessage, this.errorMessageClass);
131
+ },
132
+
133
+ showMessage: function (message, className) {
134
+ this.clearMessageContainer();
135
+ var messageElement = new Element('p', {'class': className}).update(this.prepareMessage(message));
136
+ this.messageContainer.appendChild(messageElement);
137
+ },
138
+
139
+ clearMessageContainer: function () {
140
+ this.messageContainer.update('');
141
+ },
142
+
143
+ prepareMessage: function (message) {
144
+ if ((typeof message) == 'string') {
145
+ return message;
146
+ }
147
+ if (Array.isArray(message)) {
148
+ return message.join("<br/>");
149
+ }
150
+ return '';
151
+ },
152
+
153
+ clearForm: function() {
154
+ var me = this;
155
+ $H(this.formElementSelectorList).map().each(function(elementSelector) {
156
+ $(me.formContainerId + '_' + elementSelector.key).setValue('');
157
+ });
158
+ }
159
+ });
160
+
161
+ var contactForm = new NekloCoreContact({
162
+ 'sendUrl': '<?php echo $this->getUrl('adminhtml/neklo_core_contact/send'); ?>',
163
+
164
+ 'successMessage': [
165
+ '<?php echo $this->jsQuoteEscape($this->__("Thank you for your request.")); ?>',
166
+ '<?php echo $this->jsQuoteEscape($this->__("We'll respond as soon as possible.")); ?>',
167
+ '<?php echo $this->jsQuoteEscape($this->__("We'll send copy of your request to your email.")); ?>'
168
+ ],
169
+ 'errorMessage': [
170
+ '<?php echo $this->jsQuoteEscape($this->__('Oops! Something went wrong!')); ?>'
171
+ ],
172
+
173
+ 'successMessageClass': 'success',
174
+ 'errorMessageClass': 'error',
175
+
176
+ 'formContainerId' : '<?php echo $this->getContainerId(); ?>',
177
+ 'formElementSelectorList': {
178
+ 'name': ['required-entry'],
179
+ 'email': ['required-entry', 'validate-email'],
180
+ 'subject': ['required-entry'],
181
+ 'reason': ['required-entry'],
182
+ 'other_reason': ['required-entry'],
183
+ 'message': ['required-entry']
184
+ },
185
+
186
+ 'sendButtonId': 'neklo_core_contact_send',
187
+ 'loadingMaskId': 'loading-mask',
188
+ 'messageContainerSelector': '.neklo_core_message.contact'
189
+ });
190
+ </script>
app/design/adminhtml/default/default/template/neklo/core/system/contact/header.phtml ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php /* @var $this Neklo_Core_Block_System_Contact_Header */ ?>
2
+ <h4><?php echo $this->__('Contact Neklo Support Team or visit <a href="%s" target="_blank">%s</a> for additional information', $this->getStoreUrl(), $this->getStoreLabel()); ?></h4>
app/design/adminhtml/default/default/template/neklo/core/system/extension/list.phtml ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php /* @var $this Neklo_Core_Block_System_Extension_List */ ?>
2
+ <h4><?php echo $this->__('Installed Neklo Extensions') ?></h4>
3
+ <?php $moduleConfigList = $this->getExtensionList(); ?>
4
+ <ul id="neklo_core_extension_list">
5
+ <?php foreach ($moduleConfigList as $moduleCode => $moduleConfig): ?>
6
+ <?php if (!$this->canShowExtension($moduleCode)) continue; ?>
7
+ <li class="neklo-item">
8
+ <?php if ($this->getExtensionUrl($moduleCode)): ?>
9
+ <a class="neklo-link" href="<?php echo $this->getExtensionUrl($moduleCode); ?>" target="_blank">
10
+ <?php endif; ?>
11
+ <div class="ovh">
12
+ <div class="neklo-row neklo-ext-name"><?php echo $this->getExtensionName($moduleCode); ?> <?php echo $this->getExtensionVersion($moduleConfig); ?></div>
13
+ <div class="neklo-img neklo-row"><img src="<?php echo $this->getImageUrl($moduleCode); ?>"/></div>
14
+ <?php if ($this->isExtensionVersionOutdated($moduleCode, $moduleConfig)): ?>
15
+ <?php echo $this->__('New release %s is available', $this->getLastExtensionVersion($moduleCode)); ?> <img src="<?php echo $this->getSkinUrl('neklo/core/images/update.gif'); ?>" alt="">
16
+ <?php else: ?>
17
+ <?php echo $this->__('Your version is up to date'); ?> <img src="<?php echo $this->getSkinUrl('neklo/core/images/ok.gif'); ?>" alt="">
18
+ <?php endif; ?>
19
+ </div>
20
+ <?php if ($this->getExtensionUrl($moduleCode)): ?>
21
+ </a>
22
+ <?php endif; ?>
23
+ </li>
24
+ <?php endforeach; ?>
25
+ </ul>
app/design/adminhtml/default/default/template/neklo/core/system/subscribe/button.phtml CHANGED
@@ -1,161 +1,180 @@
1
- <?php /* @var $this Neklo_Core_Block_System_Newsletter_Subscribe_Button */ ?>
2
- <?php echo $this->getButtonHtml(); ?>
3
- <div class="neklo_core_message"></div>
4
- <script>
5
- var NekloCoreSubscribe = Class.create({
6
- initialize: function (config) {
7
- this.initConfig(config);
8
- this.initElements();
9
- this.initObservers();
10
- },
11
-
12
- initConfig: function (config) {
13
- this.config = config;
14
- this.subscribeUrl = this.config.subscribeUrl || '';
15
-
16
- this.successMessage = this.config.successMessage || '';
17
- this.errorMessage = this.config.errorMessage || '';
18
-
19
- this.successMessageClass = this.config.successMessageClass || '';
20
- this.errorMessageClass = this.config.errorMessageClass || '';
21
-
22
-
23
- this.formContainerId = this.config.formContainerId || '';
24
- this.formElementSelectorList = this.config.formElementSelectorList || [];
25
- },
26
-
27
- initElements: function () {
28
- this.subscribeButton = $(this.config.subscribeButtonId) || null;
29
- this.loadingMask = $(this.config.loadingMaskId) || null;
30
- this.messageContainer = $$(this.config.messageContainerSelector).first() || null;
31
- },
32
-
33
- initObservers: function () {
34
- if (this.subscribeButton) {
35
- this.subscribeButton.observe('click', this.subscribe.bind(this));
36
- }
37
- },
38
-
39
- subscribe: function () {
40
- if (!this.validate()) {
41
- return;
42
- }
43
-
44
- var me = this;
45
- var subscribeData = {};
46
- this.formElementSelectorList.each(function (elementSelector) {
47
- subscribeData[elementSelector] = $(me.formContainerId + '_' + elementSelector).getValue();
48
- });
49
-
50
- new Ajax.Request(
51
- this.subscribeUrl,
52
- {
53
- method: 'post',
54
- parameters: subscribeData,
55
- onCreate: this._onSubscribeCreate.bind(this),
56
- onComplete: this._onSubscribeComplete.bind(this),
57
- onSuccess: this._onSubscribeSuccess.bind(this),
58
- onFailure: this._onSubscribeFailure.bind(this)
59
- }
60
- );
61
- },
62
-
63
- validate: function () {
64
- var me = this;
65
- var result = true;
66
- this.formElementSelectorList.each(function (elementSelector) {
67
- result = Validation.validate($(me.formContainerId + '_' + elementSelector));
68
- });
69
- return result;
70
- },
71
-
72
- showLoadingMask: function () {
73
- if (this.loadingMask) {
74
- this.loadingMask.show();
75
- }
76
- },
77
-
78
- hideLoadingMask: function () {
79
- if (this.loadingMask) {
80
- this.loadingMask.hide();
81
- }
82
- },
83
-
84
- _onSubscribeCreate: function () {
85
- this.clearMessageContainer();
86
- this.showLoadingMask();
87
- },
88
-
89
- _onSubscribeComplete: function () {
90
- this.hideLoadingMask();
91
- },
92
-
93
- _onSubscribeSuccess: function (response) {
94
- try {
95
- var result = response.responseText.evalJSON();
96
- if (typeof(result.success) != 'undefined') {
97
- if (result.success) {
98
- this.showSuccess();
99
- } else {
100
- this.showError();
101
- }
102
- }
103
- } catch (e) {
104
- this.showError();
105
- }
106
- },
107
-
108
- _onSubscribeFailure: function () {
109
- this.showError();
110
- },
111
-
112
- showSuccess: function () {
113
- this.showMessage(this.successMessage, this.successMessageClass);
114
- },
115
-
116
- showError: function () {
117
- this.showMessage(this.errorMessage, this.errorMessageClass);
118
- },
119
-
120
- showMessage: function (message, className) {
121
- this.clearMessageContainer();
122
- var messageElement = new Element('p', {'class': className}).update(message);
123
- this.messageContainer.appendChild(messageElement);
124
- },
125
-
126
- clearMessageContainer: function () {
127
- this.messageContainer.update('');
128
- }
129
- });
130
-
131
- var subscribeForm = new NekloCoreSubscribe({
132
- 'subscribeUrl': '<?php echo $this->getUrl('adminhtml/neklo_core_newsletter/subscribe'); ?>',
133
-
134
- 'successMessage': '<?php echo $this->__('Successfully subscribed'); ?>',
135
- 'errorMessage': '<?php echo $this->__('Subscribe error'); ?>',
136
-
137
- 'successMessageClass': 'success',
138
- 'errorMessageClass': 'error',
139
-
140
- 'formContainerId' : '<?php echo $this->getContainerId(); ?>',
141
- 'formElementSelectorList': ['name', 'email'],
142
-
143
- 'subscribeButtonId': 'neklo_core_subscribe',
144
- 'loadingMaskId': 'loading-mask',
145
- 'messageContainerSelector': '.neklo_core_message'
146
- });
147
- </script>
148
- <style>
149
- .neklo_core_message {
150
- text-align: center;
151
- padding: 5px 0;
152
- font-weight: bold;
153
- width: 280px;
154
- }
155
- .neklo_core_message .error {
156
- color: #D40707;
157
- }
158
- .neklo_core_message .success {
159
- color: #3d6611;
160
- }
161
- </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php /* @var $this Neklo_Core_Block_System_Newsletter_Subscribe_Button */ ?>
2
+ <?php echo $this->getButtonHtml(); ?>
3
+ <div class="neklo_core_message subscribe"></div>
4
+ <script>
5
+ var NekloCoreSubscribe = Class.create({
6
+ initialize: function (config) {
7
+ this.initConfig(config);
8
+ this.initElements();
9
+ this.initObservers();
10
+ },
11
+
12
+ initConfig: function (config) {
13
+ this.config = config;
14
+ this.subscribeUrl = this.config.subscribeUrl || '';
15
+
16
+ this.successMessage = this.config.successMessage || '';
17
+ this.errorMessage = this.config.errorMessage || '';
18
+
19
+ this.successMessageClass = this.config.successMessageClass || '';
20
+ this.errorMessageClass = this.config.errorMessageClass || '';
21
+
22
+
23
+ this.formContainerId = this.config.formContainerId || '';
24
+ this.formElementSelectorList = this.config.formElementSelectorList || [];
25
+ },
26
+
27
+ initElements: function () {
28
+ this.sendButton = $(this.config.subscribeButtonId) || null;
29
+ this.loadingMask = $(this.config.loadingMaskId) || null;
30
+ this.messageContainer = $$(this.config.messageContainerSelector).first() || null;
31
+ },
32
+
33
+ initObservers: function () {
34
+ if (this.sendButton) {
35
+ this.sendButton.observe('click', this.subscribe.bind(this));
36
+ }
37
+ },
38
+
39
+ subscribe: function () {
40
+ if (!this.subscribeUrl) {
41
+ return;
42
+ }
43
+ if (!this.validate()) {
44
+ return;
45
+ }
46
+
47
+ var me = this;
48
+ var subscribeData = {};
49
+ $H(this.formElementSelectorList).map().each(function(elementSelector) {
50
+ if (Validation.isVisible($(me.formContainerId + '_' + elementSelector.key))) {
51
+ subscribeData[elementSelector.key] = $(me.formContainerId + '_' + elementSelector.key).getValue();
52
+ }
53
+ });
54
+
55
+ new Ajax.Request(
56
+ this.subscribeUrl,
57
+ {
58
+ method: 'post',
59
+ parameters: subscribeData,
60
+ onCreate: this._onSubscribeCreate.bind(this),
61
+ onComplete: this._onSubscribeComplete.bind(this),
62
+ onSuccess: this._onSubscribeSuccess.bind(this),
63
+ onFailure: this._onSubscribeFailure.bind(this)
64
+ }
65
+ );
66
+ },
67
+
68
+ validate: function () {
69
+ var me = this;
70
+ var result = true;
71
+ $H(this.formElementSelectorList).map().each(function(elementSelector) {
72
+ var element = $(me.formContainerId + '_' + elementSelector.key);
73
+ elementSelector.value.each(function(className) {
74
+ element.addClassName(className);
75
+ });
76
+ result = Validation.validate($(me.formContainerId + '_' + elementSelector.key)) && result;
77
+ elementSelector.value.each(function(className) {
78
+ element.removeClassName(className);
79
+ });
80
+ });
81
+ return result;
82
+ },
83
+
84
+ showLoadingMask: function () {
85
+ if (this.loadingMask) {
86
+ this.loadingMask.show();
87
+ }
88
+ },
89
+
90
+ hideLoadingMask: function () {
91
+ if (this.loadingMask) {
92
+ this.loadingMask.hide();
93
+ }
94
+ },
95
+
96
+ _onSubscribeCreate: function () {
97
+ this.clearMessageContainer();
98
+ this.showLoadingMask();
99
+ },
100
+
101
+ _onSubscribeComplete: function () {
102
+ this.hideLoadingMask();
103
+ },
104
+
105
+ _onSubscribeSuccess: function (response) {
106
+ try {
107
+ var result = response.responseText.evalJSON();
108
+ if (typeof(result.success) != 'undefined') {
109
+ if (result.success) {
110
+ this.showSuccess();
111
+ this.clearForm();
112
+ } else {
113
+ this.showError();
114
+ }
115
+ }
116
+ } catch (e) {
117
+ this.showError();
118
+ }
119
+ },
120
+
121
+ _onSubscribeFailure: function () {
122
+ this.showError();
123
+ },
124
+
125
+ showSuccess: function () {
126
+ this.showMessage(this.successMessage, this.successMessageClass);
127
+ },
128
+
129
+ showError: function () {
130
+ this.showMessage(this.errorMessage, this.errorMessageClass);
131
+ },
132
+
133
+ showMessage: function (message, className) {
134
+ this.clearMessageContainer();
135
+ var messageElement = new Element('p', {'class': className}).update(this.prepareMessage(message));
136
+ this.messageContainer.appendChild(messageElement);
137
+ },
138
+
139
+ clearMessageContainer: function () {
140
+ this.messageContainer.update('');
141
+ },
142
+
143
+ prepareMessage: function (message) {
144
+ if ((typeof message) == 'string') {
145
+ return message;
146
+ }
147
+ if (Array.isArray(message)) {
148
+ return message.join("<br/>");
149
+ }
150
+ return '';
151
+ },
152
+
153
+ clearForm: function() {
154
+ var me = this;
155
+ $H(this.formElementSelectorList).map().each(function(elementSelector) {
156
+ $(me.formContainerId + '_' + elementSelector.key).setValue('');
157
+ });
158
+ }
159
+ });
160
+
161
+ var subscribeForm = new NekloCoreSubscribe({
162
+ 'subscribeUrl': '<?php echo $this->getUrl('adminhtml/neklo_core_newsletter/subscribe'); ?>',
163
+
164
+ 'successMessage': '<?php echo $this->jsQuoteEscape($this->__('Successfully subscribed')); ?>',
165
+ 'errorMessage': '<?php echo $this->jsQuoteEscape($this->__('Oops! Something went wrong!')); ?>',
166
+
167
+ 'successMessageClass': 'success',
168
+ 'errorMessageClass': 'error',
169
+
170
+ 'formContainerId' : '<?php echo $this->getContainerId(); ?>',
171
+ 'formElementSelectorList': {
172
+ 'name': ['required-entry'],
173
+ 'email': ['required-entry', 'validate-email']
174
+ },
175
+
176
+ 'subscribeButtonId': 'neklo_core_subscribe',
177
+ 'loadingMaskId': 'loading-mask',
178
+ 'messageContainerSelector': '.neklo_core_message.subscribe'
179
+ });
180
+ </script>
app/design/adminhtml/default/default/template/neklo/instagram/reload.phtml ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <script type="text/javascript">
2
+ window.opener.location.reload(false);
3
+ window.close();
4
+ </script>
app/design/adminhtml/default/default/template/neklo/instagram/system/config/oauth/connect.phtml ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php /* @var $this Neklo_Instagram_Block_Adminhtml_System_Config_Frontend_Oauth_Button */ ?>
2
+ <?php echo $this->getButtonHtml(); ?>
3
+ <script type="text/javascript">
4
+ var popupWidth = 640;
5
+ var popupHeight = 560;
6
+ var popupLeftOffset = screen.width / 2 - 640 / 2;
7
+ var popupTopOffset = screen.height / 2 - 480 / 2;
8
+
9
+ var button = $('<?php echo $this->getButton()->getId(); ?>');
10
+ if (button) {
11
+ Event.observe(button, 'click', function(e) {
12
+ Event.stop(e);
13
+ popWin(
14
+ '<?php echo $this->getLoginUrl(); ?>',
15
+ 'instagram_oauth',
16
+ 'width=' + popupWidth + ',height=' + popupHeight + ',left=' + popupLeftOffset + ',top=' + popupTopOffset + ',location=no,status=no,menubar=no,toolbar=no,resizable=no,scrollbars=no'
17
+ );
18
+ });
19
+ }
20
+ </script>
app/design/adminhtml/default/default/template/neklo/instagram/system/config/oauth/disconnect.phtml ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php /* @var $this Neklo_Instagram_Block_Adminhtml_System_Config_Frontend_Oauth_Disconnect */ ?>
2
+ <?php echo $this->getButtonHtml(); ?>
3
+ <script type="text/javascript">
4
+ var button = $('<?php echo $this->getButton()->getId(); ?>');
5
+ if (button) {
6
+ Event.observe(button, 'click', function(e) {
7
+ Event.stop(e);
8
+ confirmSetLocation('<?php echo $this->__('Are you sure?') ?>', '<?php echo $this->getDisconnectUrl(); ?>');
9
+ });
10
+ }
11
+ </script>
app/design/frontend/base/default/template/neklo_instagram/widget/feed.phtml CHANGED
@@ -1,24 +1,20 @@
1
- <?php
2
- $images = $this->getImages();
3
- $hashtag = $this->getHashtag();
4
- ?>
5
- <?php if (count($images) || $hashtag) : ?>
6
- <div class="neklo-instagram">
7
- <?php if ($this->getTitle()) : ?>
8
- <div class="neklo-instagram-title">
9
- <span><?php echo $this->escapeHtml(str_replace('%s', $hashtag, $this->getTitle())) ?></span>
10
- </div>
11
- <?php endif; ?>
12
-
13
- <?php if ($this->getDescription()) : ?>
14
- <div class="neklo-instagram-description">
15
- <span><?php echo nl2br($this->escapeHtml(str_replace('%s', $hashtag, $this->getDescription()))) ?></span>
16
- </div>
17
- <?php endif; ?>
18
-
19
- <?php if (count($images)): ?>
20
  <ul class="neklo-instagram-list">
21
- <?php foreach ($images as $image) : ?>
22
  <li>
23
  <a href="<?php echo $image->getLink(); ?>" target="_blank" >
24
  <i class="neklo-instagram-over"></i>
@@ -27,6 +23,6 @@
27
  </li>
28
  <?php endforeach; ?>
29
  </ul>
30
- <?php endif; ?>
31
- </div>
32
- <?php endif; ?>
1
+ <?php /* @var $this Neklo_Instagram_Block_Widget_Feed */ ?>
2
+ <?php if ($this->canShow()): ?>
3
+ <?php $imageList = $this->getImageList(); ?>
4
+ <?php if (count($imageList)) : ?>
5
+ <div class="neklo-instagram">
6
+ <?php if ($this->getTitle()) : ?>
7
+ <div class="neklo-instagram-title">
8
+ <span><?php echo $this->escapeHtml($this->getTitle()) ?></span>
9
+ </div>
10
+ <?php endif; ?>
11
+ <?php if ($this->getDescription()) : ?>
12
+ <div class="neklo-instagram-description">
13
+ <span><?php echo nl2br($this->escapeHtml($this->getDescription())) ?></span>
14
+ </div>
15
+ <?php endif; ?>
 
 
 
 
16
  <ul class="neklo-instagram-list">
17
+ <?php foreach ($imageList as $image) : ?>
18
  <li>
19
  <a href="<?php echo $image->getLink(); ?>" target="_blank" >
20
  <i class="neklo-instagram-over"></i>
23
  </li>
24
  <?php endforeach; ?>
25
  </ul>
26
+ </div>
27
+ <?php endif; ?>
28
+ <?php endif; ?>
app/etc/modules/Neklo_Instagram.xml CHANGED
@@ -1,13 +1,13 @@
1
- <?xml version="1.0"?>
2
- <config>
3
- <modules>
4
- <Neklo_Instagram>
5
- <active>true</active>
6
- <codePool>community</codePool>
7
- <depends><Neklo_Core /></depends>
8
- <extension_name>Neklo Instagram Widget</extension_name>
9
- <free>1</free>
10
- <url></url>
11
- </Neklo_Instagram>
12
- </modules>
13
  </config>
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Neklo_Instagram>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ <depends>
8
+ <Neklo_Core/>
9
+ </depends>
10
+ <free>1</free>
11
+ </Neklo_Instagram>
12
+ </modules>
13
  </config>
app/locale/en_US/Neklo_Instagram.csv CHANGED
@@ -1,18 +1,19 @@
1
- {how-to-get-user-id},"<a href='http://jelled.com/instagram/lookup-user-id' target='_blank'>How to get?</a>"
2
- API Client ID,API Client ID
3
- By Hashtag,By Hashtag
4
- By Product Hashtag,By Product Hashtag
5
- By User ID,By User ID
6
- Cache Lifetime,Cache Lifetime
7
- Description,Description
8
- General,General
9
- Hashtag,Hashtag
10
- In seconds,In seconds
11
- Limit,Limit
12
- Mode,Mode
13
- Neklo Instagram Template,Neklo Instagram Template
14
- Template,Template
15
- Thumbnail Height,Thumbnail Height
16
- Thumbnail Width,Thumbnail Width
17
- Title,Title
 
18
  User ID,User ID
1
+ {how-to-get-user-id},"<a href='http://jelled.com/instagram/lookup-user-id' target='_blank'>How to get?</a>"
2
+ API Client ID,API Client ID
3
+ By Hashtag,By Hashtag
4
+ By Product Hashtag,By Product Hashtag
5
+ By User ID,By User ID
6
+ By User Name,By User Name
7
+ Cache Lifetime,Cache Lifetime
8
+ Description,Description
9
+ General,General
10
+ Hashtag,Hashtag
11
+ In seconds,In seconds
12
+ Limit,Limit
13
+ Mode,Mode
14
+ Instagram Widget Default Template,Instagram Widget Default Template
15
+ Template,Template
16
+ Thumbnail Height,Thumbnail Height
17
+ Thumbnail Width,Thumbnail Width
18
+ Title,Title
19
  User ID,User ID
package.xml CHANGED
@@ -1,18 +1,2 @@
1
  <?xml version="1.0"?>
2
- <package>
3
- <name>Neklo_Instagram</name>
4
- <version>1.0.3</version>
5
- <stability>stable</stability>
6
- <license>License</license>
7
- <channel>community</channel>
8
- <extends/>
9
- <summary>Summary</summary>
10
- <description>Description</description>
11
- <notes>* Instagram API v2</notes>
12
- <authors><author><name>NEKLO</name><user>NEKLO</user><email>info@neklo.com</email></author></authors>
13
- <date>2016-01-21</date>
14
- <time>10:17:33</time>
15
- <contents><target name="magecommunity"><dir name="Neklo"><dir name="Core"><dir name="Block"><dir name="System"><file name="Abstract.php" hash="ca1a1083ae0fe2b0d7bcffe49313ed72"/><file name="Contact.php" hash="b9d03eda3b0ff0b8ffd17a777bc36d9b"/><file name="Extensions.php" hash="fafa6cb1e0d5b5ce5538a6d01ad6581b"/><dir name="Newsletter"><dir name="Subscribe"><file name="Button.php" hash="c24e57030e1a6d16611eb516a9249c34"/></dir><file name="Subscribe.php" hash="7b9b021aa6f12c0eff8576c4cb6cd60d"/></dir><file name="Newsletter.php" hash="46a84ace83bf1a4a81a3e4bf90272c6c"/></dir></dir><dir name="Helper"><file name="Data.php" hash="e13a6d27a50ea228c8751e6465c8f463"/></dir><dir name="Model"><file name="Feed.php" hash="8a669a60ad96195af2ff706c1e3ec26e"/><file name="Observer.php" hash="dea6141e7f7bb7acde44f242d0ae7083"/></dir><dir name="controllers"><dir name="Adminhtml"><dir name="Neklo"><dir name="Core"><file name="ContactController.php" hash="dcf7ef46b142e9d886c67b2d760ef652"/><file name="NewsletterController.php" hash="86be65da9dadc1a26ebc6133be52f834"/></dir></dir></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="68b00ad4118462d74b0c0a7126063462"/><file name="config.xml" hash="be54033dcedd6d17a68907b2c52b8d32"/><file name="system.xml" hash="66e1ccd2fc1c3fdd511dc99a8575009d"/></dir></dir><dir name="Instagram"><dir name="Block"><dir name="Widget"><file name="Feed.php" hash="c9e5fcf2f34d14b6599a2b9c6617d728"/></dir></dir><dir name="Helper"><file name="Data.php" hash="6c57bb70ad4c6f211ef9c1e3033c0dd8"/></dir><dir name="Model"><dir name="Instagram"><file name="Api.php" hash="5505107ddc2bd1e7f1bb49b00d20bdf2"/></dir><file name="Instagram.php" hash="3efb7914780885c2154463afa8fb1cab"/></dir><dir name="etc"><file name="adminhtml.xml" hash="220b289dd031e83a958f763a4bd0f357"/><file name="config.xml" hash="292a4352186fc68bb7b181d5778f2449"/><file name="system.xml" hash="5dabb11896bf8d3f49549610303d1fc9"/><file name="widget.xml" hash="783d275193939911eaebfa235a478d63"/></dir><dir name="sql"><dir name="neklo_instagram_setup"><file name="mysql4-install-1.0.0.php" hash="a4f85234f2a790c7dab234f9f16b998e"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="template"><dir name="neklo"><dir name="core"><dir name="system"><dir name="subscribe"><file name="button.phtml" hash="4e9fe3dfa9e291976ff45c2e25ce7b10"/></dir></dir></dir></dir></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="neklo_instagram.xml" hash="980370a95cf078ec32ef6d8f786f0d20"/></dir><dir name="template"><dir name="neklo_instagram"><dir name="widget"><file name="feed.phtml" hash="143033929ee8f5bf4a97f8f24c43a9fc"/></dir></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Neklo_Core.xml" hash="335032ff690c5272626dca9106642680"/><file name="Neklo_Instagram.xml" hash="f46651fccc8826b06926dfcba4f74b48"/></dir></target><target name="magelocale"><dir name="en_US"><file name="Neklo_Core.csv" hash="c6abfbb8be878de9c02339e2ecfc4e16"/><file name="Neklo_Instagram.csv" hash="8dd4e74980857f2dc653531bb44c296b"/></dir></target><target name="mageskin"><dir name="frontend"><dir name="base"><dir name="default"><dir name="neklo"><dir name="instagram"><dir name="css"><file name="style.css" hash="18d2da6d94b485125684a0f698b16dcc"/></dir><dir name="sass"><dir name="mixin"><file name="_mixin.scss" hash="2033dcd7ddd64684d5fa380bb2983421"/></dir><file name="style.scss" hash="fd78ff95a42fd521693f2233431eda5b"/></dir></dir></dir></dir></dir></dir></target></contents>
16
- <compatible/>
17
- <dependencies><required><php><min>5.2.7</min><max>6.0.0</max></php></required></dependencies>
18
- </package>
1
  <?xml version="1.0"?>
2
+ <package><name>Neklo_Instagram</name><version>1.1.0</version><stability>stable</stability><license>License</license><channel>community</channel><extends></extends><summary>New instagram api support added</summary><description>Free Magento Community extension that adds Instagram to your online store.</description><notes>New instagram api support added</notes><authors><author><name>NEKLO</name><user>NEKLO</user><email>info@neklo.com</email></author></authors><date>2016-06-03</date><time>3:49:40</time><compatible></compatible><dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies><contents><target name="mage"><dir name="app"><dir name="etc"><dir name="modules"><file name="Neklo_Core.xml" hash="335032ff690c5272626dca9106642680"/><file name="Neklo_Instagram.xml" hash="067c0c1356e12cb92baa0661d5be032f"/></dir></dir><dir name="code"><dir name="community"><dir name="Neklo"><dir name="Instagram"><dir name="etc"><file name="adminhtml.xml" hash="61d458d177562d7d0911574267601ffa"/><file name="config.xml" hash="4d18887e9dcb89a4fe79cbcacbd14248"/><file name="system.xml" hash="8a1fc85d0a95df0a883c8a27ee1772e7"/><file name="widget.xml" hash="bc457cb843224b227402220fa130d087"/></dir><dir name="controllers"><dir name="Adminhtml"><dir name="Neklo"><dir name="Instagram"><file name="ApiController.php" hash="810f7bf587e560af13876aac39098ad2"/></dir></dir></dir></dir><dir name="Block"><dir name="Widget"><file name="Feed.php" hash="f7d2e2b4118d1da76cc0ff0b03a90a85"/></dir><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Frontend"><file name="Oauth.php" hash="f31ead7dc8bfc0041b0a9983eec564e0"/><file name="Status.php" hash="8e1250a678b93d1bef87094ff87b6505"/><dir name="Oauth"><file name="Connect.php" hash="2f5374faaf6c5776f97a886bb27b543a"/><file name="Disconnect.php" hash="6bd4158fab8ecf9f437d3feacd0881ce"/></dir></dir></dir></dir></dir></dir><dir name="sql"><dir name="neklo_instagram_setup"><file name="mysql4-install-1.0.0.php" hash="a6857b5b44abb5870ec20455a8e204d9"/></dir></dir><dir name="Model"><file name="Instagram.php" hash="b5ec40e45e05f713459c3f494dde1716"/><dir name="Source"><file name="Mode.php" hash="389e64a529cb0763c88f6a95e18d9aa2"/></dir><dir name="Instagram"><file name="Api.php" hash="490df368f82d4169056dd773ac2738f4"/></dir><dir name="System"><dir name="Config"><dir name="Backend"><file name="Empty.php" hash="f9c2bb9852a805356c9240ccd5a8a1ef"/></dir></dir></dir></dir><dir name="Helper"><file name="Config.php" hash="9da4ee22f4e207227a40c41201f8f6eb"/><file name="Data.php" hash="40b22c15f85d55b7a2aa734f1457b15e"/></dir></dir><dir name="Core"><dir name="etc"><file name="adminhtml.xml" hash="68b00ad4118462d74b0c0a7126063462"/><file name="config.xml" hash="3fc06c04d63578d873a4d4145785e4c0"/><file name="system.xml" hash="f9ee62f79b22584cc6180ec5e8049539"/></dir><dir name="controllers"><dir name="Adminhtml"><dir name="Neklo"><dir name="Core"><file name="ContactController.php" hash="fe735a9c3c0ad9c4ecb88edd009059a9"/><file name="NewsletterController.php" hash="b9342c80bf94c29a463251b1c7b02705"/></dir></dir></dir></dir><dir name="Block"><dir name="System"><file name="Contact.php" hash="a0e89ca48de64bb8526c35598f99802b"/><file name="Extension.php" hash="8cd6609bd4f00bf8a8f5913d20e98e65"/><dir name="Contact"><file name="Header.php" hash="a6c4f8dbf002a0d2f6be0ea37445a562"/><file name="Send.php" hash="333d3059033faa826ef3781946676b16"/><dir name="Send"><file name="Button.php" hash="c94e2ae59246a968d7eb2e89e63485c8"/></dir></dir><dir name="Newsletter"><file name="Subscribe.php" hash="1015b8e49758e40c829667e94bb06220"/><dir name="Subscribe"><file name="Button.php" hash="98162d3c3280bdc3da75c90c45fc9500"/></dir></dir><dir name="Extension"><file name="List.php" hash="0006ff459c6b19de9349fa31c8be6b2b"/></dir></dir></dir><dir name="Model"><file name="Feed.php" hash="b5e0d2343b2c9db1f4d86ca0e8b3a922"/><file name="Observer.php" hash="dfc8c917e3f3882d1d99c734831c6e0b"/><dir name="Source"><file name="Reason.php" hash="02eb3c4cfe3433e5a8194862aef636c4"/><dir name="Subscription"><file name="Type.php" hash="616c3f7e7e4ebe3e42e16d54d159d378"/></dir></dir><dir name="System"><dir name="Config"><dir name="Backend"><file name="Empty.php" hash="2af2d53c7c56b9ea4a148a2862da224b"/></dir></dir></dir><dir name="Feed"><file name="Extension.php" hash="1ff201b02db7827df350b11c19902fa2"/></dir></dir><dir name="Helper"><file name="Config.php" hash="42eff18ca97b961e1186a790abcb8690"/><file name="Data.php" hash="5492cb13c72b737d85e9009f0f623336"/><file name="Extension.php" hash="c0c987bd848e5270ec31544460438eab"/></dir></dir></dir></dir></dir><dir name="design"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><dir name="neklo"><file name="core.xml" hash="8851b2c111c8e0745fb78af2bb57e6a6"/><file name="instagram.xml" hash="6993984d71d814cf9da9587eb2b8d169"/></dir></dir><dir name="template"><dir name="neklo"><dir name="core"><dir name="system"><dir name="contact"><file name="button.phtml" hash="f7b5f21ddb974aa32c888c29f3057d18"/><file name="header.phtml" hash="3c0a401955a9b2bac799aa65b5bf7a81"/></dir><dir name="extension"><file name="list.phtml" hash="29378800cc0a7488badb2698a02220d7"/></dir><dir name="subscribe"><file name="button.phtml" hash="865b84befba4d00e6a1e4de2b989776e"/></dir></dir></dir><dir name="instagram"><file name="reload.phtml" hash="61baa41a07077596ee66bcfe01d6bad6"/><dir name="system"><dir name="config"><dir name="oauth"><file name="connect.phtml" hash="1125acc9777d77c9648ab9859e743829"/><file name="disconnect.phtml" hash="f43c3861f99228fef4618d63997f02f1"/></dir></dir></dir></dir></dir></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="neklo_instagram.xml" hash="980370a95cf078ec32ef6d8f786f0d20"/></dir><dir name="template"><dir name="neklo_instagram"><dir name="widget"><file name="feed.phtml" hash="ffc05dfd132f1cb2334d724b205e8e19"/></dir></dir></dir></dir></dir></dir></dir><dir name="locale"><dir name="en_US"><file name="Neklo_Core.csv" hash="c6abfbb8be878de9c02339e2ecfc4e16"/><file name="Neklo_Instagram.csv" hash="dcead4bc71dfaaceb20875ae801a63b2"/></dir></dir></dir><dir name="skin"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="neklo"><dir name="core"><dir name="images"><file name="ok.gif" hash="a38bc2ee6e116e39c6e2e3013ee50f5e"/><file name="update.gif" hash="8342e11f7739fcfa25134707f0536ed6"/></dir><dir name="css"><file name="style.css" hash="77e35507d6f2e748afc08f11f322120d"/></dir></dir><dir name="instagram"><dir name="css"><file name="styles.css" hash="df91963d1eedebd6d4e9d0f1619b784b"/></dir></dir></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="neklo"><dir name="instagram"><dir name="sass"><file name="style.scss" hash="12dd85564e0664258ee1ff950276adab"/><dir name="mixin"><file name="_mixin.scss" hash="d5c2ae437ecf2c7f23fe5823563acf45"/></dir></dir><dir name="css"><file name="style.css" hash="7b2330ee08465bc44daa82263cee7c9a"/></dir></dir></dir></dir></dir></dir></dir></target></contents></package>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
skin/adminhtml/default/default/neklo/core/css/style.css ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .ovh{
2
+ overflow: hidden;
3
+ display: inline-block;
4
+ font-size: 16px;
5
+ color: #494848;
6
+ text-align: center;
7
+ }
8
+ .neklo-img{
9
+ width: 150px;
10
+ height: 150px;
11
+ margin: 0 auto;
12
+ }
13
+ .neklo-img img{
14
+ width: 100%;
15
+ height: 100%;
16
+ }
17
+ .neklo-row{
18
+ margin-bottom: 20px;
19
+ }
20
+ .neklo-link, .neklo-link:hover{
21
+ color: #494848;
22
+ text-decoration: none;
23
+ }
24
+ .neklo-link:hover .neklo-ext-name{
25
+ text-decoration: underline;
26
+ }
27
+ .neklo-ext-name{
28
+ font-weight: bold;
29
+ min-height: 36px;
30
+ margin-bottom: 10px;
31
+ }
32
+ .neklo-item{
33
+ border: 1px solid #ccc;
34
+ display: inline-block;
35
+ padding: 20px;
36
+ margin: 0 20px 20px 0 !important;
37
+ vertical-align: top;
38
+ width: 270px;
39
+ text-align: center;
40
+ }
41
+ .neklo_core_message {
42
+ text-align: center;
43
+ padding: 5px 0;
44
+ font-weight: bold;
45
+ width: 280px;
46
+ }
47
+ .neklo_core_message .error {
48
+ color: #D40707;
49
+ }
50
+ .neklo_core_message .success {
51
+ color: #3d6611;
52
+ }
skin/adminhtml/default/default/neklo/core/images/ok.gif ADDED
Binary file
skin/adminhtml/default/default/neklo/core/images/update.gif ADDED
Binary file
skin/adminhtml/default/default/neklo/instagram/css/styles.css ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ .instagram_status {
2
+ width: 280px;
3
+ text-align: center;
4
+ }
5
+ .instagram_status.success {
6
+ color:#008000;
7
+ }
8
+ .instagram_status.error {
9
+ color:#FF0000;
10
+ }
skin/frontend/base/default/neklo/instagram/css/style.css CHANGED
@@ -1,110 +1,110 @@
1
- /* mixins */
2
- /* sprite */
3
- /* clearfix */
4
- /* list_ib */
5
- /* list_jst */
6
- /* reset */
7
- /* hold-center */
8
- /* core-justify */
9
- /* placeholder */
10
- /* triangle */
11
- .neklo-instagram-title {
12
- text-transform: uppercase;
13
- font-size: 18px;
14
- font-weight: bold;
15
- color: #000000;
16
- text-align: center;
17
- margin-bottom: 10px;
18
- }
19
- @media screen and (max-width: 48em) {
20
- .neklo-instagram-title {
21
- font-size: 16px;
22
- }
23
- }
24
-
25
- .neklo-instagram-description {
26
- font-size: 14px;
27
- color: #000000;
28
- text-align: center;
29
- margin-bottom: 10px;
30
- }
31
- @media screen and (max-width: 48em) {
32
- .neklo-instagram-description {
33
- font-size: 12px;
34
- }
35
- }
36
-
37
- .neklo-instagram-list {
38
- margin: 20px auto;
39
- width: 80%;
40
- text-align: center;
41
- font-size: 0;
42
- }
43
- .neklo-instagram-list:after {
44
- content: ".";
45
- display: block;
46
- height: 0;
47
- clear: both;
48
- visibility: hidden;
49
- }
50
- @media screen and (max-width: 48em) {
51
- .neklo-instagram-list {
52
- width: 95%;
53
- }
54
- }
55
- .neklo-instagram-list li {
56
- display: inline-block;
57
- vertical-align: top;
58
- -moz-transition: all 0.2s ease;
59
- -o-transition: all 0.2s ease;
60
- -webkit-transition: all 0.2s ease;
61
- transition: all 0.2s ease;
62
- margin: 0 2px 2px 0;
63
- }
64
- .neklo-instagram-list li:hover .neklo-instagram-over {
65
- -moz-border-radius: 50%;
66
- -webkit-border-radius: 50%;
67
- border-radius: 50%;
68
- -moz-transform: scale(0);
69
- -ms-transform: scale(0);
70
- -webkit-transform: scale(0);
71
- transform: scale(0);
72
- }
73
- .neklo-instagram-list li:hover img {
74
- -moz-transform: scale(1.2);
75
- -ms-transform: scale(1.2);
76
- -webkit-transform: scale(1.2);
77
- transform: scale(1.2);
78
- }
79
- .neklo-instagram-list a {
80
- position: relative;
81
- overflow: hidden;
82
- display: block;
83
- }
84
- .neklo-instagram-list img {
85
- -moz-transition: all 0.2s ease;
86
- -o-transition: all 0.2s ease;
87
- -webkit-transition: all 0.2s ease;
88
- transition: all 0.2s ease;
89
- -moz-transform: scale(1);
90
- -ms-transform: scale(1);
91
- -webkit-transform: scale(1);
92
- transform: scale(1);
93
- }
94
-
95
- .neklo-instagram-over {
96
- position: absolute;
97
- left: 0;
98
- top: 0;
99
- bottom: 0;
100
- right: 0;
101
- margin: auto;
102
- background: #000000;
103
- filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=30);
104
- opacity: 0.3;
105
- -moz-transition: all 0.2s ease;
106
- -o-transition: all 0.2s ease;
107
- -webkit-transition: all 0.2s ease;
108
- transition: all 0.2s ease;
109
- z-index: 10;
110
- }
1
+ /* mixins */
2
+ /* sprite */
3
+ /* clearfix */
4
+ /* list_ib */
5
+ /* list_jst */
6
+ /* reset */
7
+ /* hold-center */
8
+ /* core-justify */
9
+ /* placeholder */
10
+ /* triangle */
11
+ .neklo-instagram-title {
12
+ text-transform: uppercase;
13
+ font-size: 18px;
14
+ font-weight: bold;
15
+ color: #000000;
16
+ text-align: center;
17
+ margin-bottom: 10px;
18
+ }
19
+ @media screen and (max-width: 48em) {
20
+ .neklo-instagram-title {
21
+ font-size: 16px;
22
+ }
23
+ }
24
+
25
+ .neklo-instagram-description {
26
+ font-size: 14px;
27
+ color: #000000;
28
+ text-align: center;
29
+ margin-bottom: 10px;
30
+ }
31
+ @media screen and (max-width: 48em) {
32
+ .neklo-instagram-description {
33
+ font-size: 12px;
34
+ }
35
+ }
36
+
37
+ .neklo-instagram-list {
38
+ margin: 20px auto;
39
+ width: 80%;
40
+ text-align: center;
41
+ font-size: 0;
42
+ }
43
+ .neklo-instagram-list:after {
44
+ content: ".";
45
+ display: block;
46
+ height: 0;
47
+ clear: both;
48
+ visibility: hidden;
49
+ }
50
+ @media screen and (max-width: 48em) {
51
+ .neklo-instagram-list {
52
+ width: 95%;
53
+ }
54
+ }
55
+ .neklo-instagram-list li {
56
+ display: inline-block;
57
+ vertical-align: top;
58
+ -moz-transition: all 0.2s ease;
59
+ -o-transition: all 0.2s ease;
60
+ -webkit-transition: all 0.2s ease;
61
+ transition: all 0.2s ease;
62
+ margin: 0 2px 2px 0;
63
+ }
64
+ .neklo-instagram-list li:hover .neklo-instagram-over {
65
+ -moz-border-radius: 50%;
66
+ -webkit-border-radius: 50%;
67
+ border-radius: 50%;
68
+ -moz-transform: scale(0);
69
+ -ms-transform: scale(0);
70
+ -webkit-transform: scale(0);
71
+ transform: scale(0);
72
+ }
73
+ .neklo-instagram-list li:hover img {
74
+ -moz-transform: scale(1.2);
75
+ -ms-transform: scale(1.2);
76
+ -webkit-transform: scale(1.2);
77
+ transform: scale(1.2);
78
+ }
79
+ .neklo-instagram-list a {
80
+ position: relative;
81
+ overflow: hidden;
82
+ display: block;
83
+ }
84
+ .neklo-instagram-list img {
85
+ -moz-transition: all 0.2s ease;
86
+ -o-transition: all 0.2s ease;
87
+ -webkit-transition: all 0.2s ease;
88
+ transition: all 0.2s ease;
89
+ -moz-transform: scale(1);
90
+ -ms-transform: scale(1);
91
+ -webkit-transform: scale(1);
92
+ transform: scale(1);
93
+ }
94
+
95
+ .neklo-instagram-over {
96
+ position: absolute;
97
+ left: 0;
98
+ top: 0;
99
+ bottom: 0;
100
+ right: 0;
101
+ margin: auto;
102
+ background: #000000;
103
+ filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=30);
104
+ opacity: 0.3;
105
+ -moz-transition: all 0.2s ease;
106
+ -o-transition: all 0.2s ease;
107
+ -webkit-transition: all 0.2s ease;
108
+ transition: all 0.2s ease;
109
+ z-index: 10;
110
+ }
skin/frontend/base/default/neklo/instagram/sass/mixin/_mixin.scss CHANGED
@@ -1,156 +1,156 @@
1
- /* mixins */
2
-
3
- @mixin breakpointmedia( $value, $operator: 'min-width', $query: 'screen') {
4
- @media #{$query} and (#{$operator}: #{$value/16}em) {
5
- @content;
6
- }
7
- }
8
-
9
- /* sprite */
10
- @mixin my-sprite($images){
11
- @include my-sprite-sprite($images);
12
- width: my-sprite-sprite-width($images);
13
- height: my-sprite-sprite-height($images);
14
- }
15
- /* clearfix */
16
- @mixin clearfix {
17
- &:after {content: "."; display: block; height: 0; clear: both; visibility: hidden;}
18
- }
19
-
20
- /* list_ib */
21
- @mixin list_ib {
22
- font-size: 0;
23
- display: table;
24
- li {display: inline-block; vertical-align: top;}
25
- }
26
-
27
- /* list_jst */
28
- @mixin list_jst {
29
- text-align: justify;
30
- line-height: 0;
31
- *text-justify: newspaper;
32
- *text-align-last: justify;
33
- *zoom:1;
34
- :after {content: ''; display: inline-block; width: 100%; height: 0; visibility: hidden;}
35
- li {display: inline-block; *display : inline; *zoom : 1; vertical-align: top; line-height: normal; text-align: left;}
36
- }
37
-
38
- /* reset */
39
- @mixin reset {
40
- padding: 0;
41
- margin: 0;
42
- border: none;
43
-
44
- li {
45
- list-style:none;
46
- }
47
- }
48
-
49
- /* hold-center */
50
- @mixin hold-center($blockWidth: auto, $blockMinWidth: 0, $blockMaxWidth: auto, $blockType: fixed) {
51
- $blockMargin: auto;
52
- @if ($blockType == fixed) {
53
- @if ($blockWidth == auto) {
54
- $blockMargin: 0;
55
- }
56
- width: $blockWidth;
57
- } @else if ($blockType == flex) {
58
- max-width: $blockMaxWidth;
59
- min-width: $blockMinWidth;
60
- } @else {
61
- width: $blockWidth;
62
- }
63
- margin: $blockMargin;
64
- }
65
-
66
- /* core-justify */
67
- @mixin core-justify() {
68
- font-size: 0;
69
- text: {
70
- align: justify;
71
- justify: newspaper;
72
- }
73
-
74
- &:after {
75
- display: inline-block;
76
- height: 0;
77
- overflow: hidden;
78
- visibility: hidden;
79
- width: 100%;
80
- content: '';
81
- }
82
-
83
- .lt-ie8 & {
84
- text-align-last: justify;
85
- zoom: 1;
86
- }
87
- }
88
-
89
- /* placeholder */
90
- @mixin placeholder {
91
- &.placeholder { @content; }
92
- &:-moz-placeholder { @content; }
93
- &::-moz-placeholder { @content; }
94
- &::-webkit-input-placeholder { @content; }
95
- }
96
-
97
- /* triangle */
98
- @mixin triangle($direction: up, $size: 5px, $color: #000000) {
99
- content: '';
100
- position: absolute;
101
- width: 0;
102
- height: 0;
103
- display: block;
104
-
105
- @if $direction == up {
106
- border-right: $size solid transparent;
107
- border-left: $size solid transparent;
108
- border-bottom: $size solid $color;
109
- border-top: none;
110
- }
111
-
112
- @if $direction == down {
113
- border-right: $size solid transparent;
114
- border-left: $size solid transparent;
115
- border-top: $size solid $color;
116
- border-bottom: none;
117
- }
118
-
119
- @if $direction == right {
120
- border-top: $size solid transparent;
121
- border-bottom: $size solid transparent;
122
- border-left: $size solid $color;
123
- border-right: none;
124
- }
125
-
126
- @if $direction == left {
127
- border-top: $size solid transparent;
128
- border-bottom: $size solid transparent;
129
- border-right: $size solid $color;
130
- border-left: none;
131
- }
132
-
133
- @if $direction == upleft {
134
- border: $size solid transparent;
135
- border-top: $size solid $color;
136
- border-left: $size solid $color;
137
- }
138
-
139
- @if $direction == upright {
140
- border: $size solid transparent;
141
- border-top: $size solid $color;
142
- border-right: $size solid $color;
143
- }
144
-
145
- @if $direction == bottom-right {
146
- border: $size solid transparent;
147
- border-bottom: $size solid $color;
148
- border-right: $size solid $color;
149
- }
150
-
151
- @if $direction == bottom-left {
152
- border: $size solid transparent;
153
- border-bottom: $size solid $color;
154
- border-left: $size solid $color;
155
- }
156
- }
1
+ /* mixins */
2
+
3
+ @mixin breakpointmedia( $value, $operator: 'min-width', $query: 'screen') {
4
+ @media #{$query} and (#{$operator}: #{$value/16}em) {
5
+ @content;
6
+ }
7
+ }
8
+
9
+ /* sprite */
10
+ @mixin my-sprite($images){
11
+ @include my-sprite-sprite($images);
12
+ width: my-sprite-sprite-width($images);
13
+ height: my-sprite-sprite-height($images);
14
+ }
15
+ /* clearfix */
16
+ @mixin clearfix {
17
+ &:after {content: "."; display: block; height: 0; clear: both; visibility: hidden;}
18
+ }
19
+
20
+ /* list_ib */
21
+ @mixin list_ib {
22
+ font-size: 0;
23
+ display: table;
24
+ li {display: inline-block; vertical-align: top;}
25
+ }
26
+
27
+ /* list_jst */
28
+ @mixin list_jst {
29
+ text-align: justify;
30
+ line-height: 0;
31
+ *text-justify: newspaper;
32
+ *text-align-last: justify;
33
+ *zoom:1;
34
+ :after {content: ''; display: inline-block; width: 100%; height: 0; visibility: hidden;}
35
+ li {display: inline-block; *display : inline; *zoom : 1; vertical-align: top; line-height: normal; text-align: left;}
36
+ }
37
+
38
+ /* reset */
39
+ @mixin reset {
40
+ padding: 0;
41
+ margin: 0;
42
+ border: none;
43
+
44
+ li {
45
+ list-style:none;
46
+ }
47
+ }
48
+
49
+ /* hold-center */
50
+ @mixin hold-center($blockWidth: auto, $blockMinWidth: 0, $blockMaxWidth: auto, $blockType: fixed) {
51
+ $blockMargin: auto;
52
+ @if ($blockType == fixed) {
53
+ @if ($blockWidth == auto) {
54
+ $blockMargin: 0;
55
+ }
56
+ width: $blockWidth;
57
+ } @else if ($blockType == flex) {
58
+ max-width: $blockMaxWidth;
59
+ min-width: $blockMinWidth;
60
+ } @else {
61
+ width: $blockWidth;
62
+ }
63
+ margin: $blockMargin;
64
+ }
65
+
66
+ /* core-justify */
67
+ @mixin core-justify() {
68
+ font-size: 0;
69
+ text: {
70
+ align: justify;
71
+ justify: newspaper;
72
+ }
73
+
74
+ &:after {
75
+ display: inline-block;
76
+ height: 0;
77
+ overflow: hidden;
78
+ visibility: hidden;
79
+ width: 100%;
80
+ content: '';
81
+ }
82
+
83
+ .lt-ie8 & {
84
+ text-align-last: justify;
85
+ zoom: 1;
86
+ }
87
+ }
88
+
89
+ /* placeholder */
90
+ @mixin placeholder {
91
+ &.placeholder { @content; }
92
+ &:-moz-placeholder { @content; }
93
+ &::-moz-placeholder { @content; }
94
+ &::-webkit-input-placeholder { @content; }
95
+ }
96
+
97
+ /* triangle */
98
+ @mixin triangle($direction: up, $size: 5px, $color: #000000) {
99
+ content: '';
100
+ position: absolute;
101
+ width: 0;
102
+ height: 0;
103
+ display: block;
104
+
105
+ @if $direction == up {
106
+ border-right: $size solid transparent;
107
+ border-left: $size solid transparent;
108
+ border-bottom: $size solid $color;
109
+ border-top: none;
110
+ }
111
+
112
+ @if $direction == down {
113
+ border-right: $size solid transparent;
114
+ border-left: $size solid transparent;
115
+ border-top: $size solid $color;
116
+ border-bottom: none;
117
+ }
118
+
119
+ @if $direction == right {
120
+ border-top: $size solid transparent;
121
+ border-bottom: $size solid transparent;
122
+ border-left: $size solid $color;
123
+ border-right: none;
124
+ }
125
+
126
+ @if $direction == left {
127
+ border-top: $size solid transparent;
128
+ border-bottom: $size solid transparent;
129
+ border-right: $size solid $color;
130
+ border-left: none;
131
+ }
132
+
133
+ @if $direction == upleft {
134
+ border: $size solid transparent;
135
+ border-top: $size solid $color;
136
+ border-left: $size solid $color;
137
+ }
138
+
139
+ @if $direction == upright {
140
+ border: $size solid transparent;
141
+ border-top: $size solid $color;
142
+ border-right: $size solid $color;
143
+ }
144
+
145
+ @if $direction == bottom-right {
146
+ border: $size solid transparent;
147
+ border-bottom: $size solid $color;
148
+ border-right: $size solid $color;
149
+ }
150
+
151
+ @if $direction == bottom-left {
152
+ border: $size solid transparent;
153
+ border-bottom: $size solid $color;
154
+ border-left: $size solid $color;
155
+ }
156
+ }
skin/frontend/base/default/neklo/instagram/sass/style.scss CHANGED
@@ -1,78 +1,78 @@
1
- @import "mixin/mixin";
2
- @import "compass/css3";
3
-
4
- .neklo-instagram-title {
5
- text-transform: uppercase;
6
- font-size: 18px;
7
- font-weight: bold;
8
- color: #000000;
9
- text-align: center;
10
- margin-bottom: 10px;
11
-
12
- @include breakpointmedia(768, 'max-width') {
13
- font-size: 16px;
14
- }
15
- }
16
-
17
- .neklo-instagram-description {
18
- font-size: 14px;
19
- color: #000000;
20
- text-align: center;
21
- margin-bottom: 10px;
22
-
23
- @include breakpointmedia(768, 'max-width') {
24
- font-size: 12px;
25
- }
26
- }
27
-
28
- .neklo-instagram-list {
29
- @include clearfix();
30
- margin: 20px auto;
31
- width: 80%;
32
- text-align: center;
33
- font-size: 0;
34
-
35
- @include breakpointmedia(768, 'max-width') {
36
- width: 95%;
37
- }
38
-
39
- li {
40
- display: inline-block;
41
- vertical-align: top;
42
- @include transition(all 0.2s ease);
43
- margin: 0 2px 2px 0;
44
-
45
- &:hover {
46
- .neklo-instagram-over {
47
- @include border-radius(50%);
48
- @include transform(scale(0));
49
- }
50
-
51
- img { @include transform(scale(1.2)); }
52
- }
53
- }
54
-
55
- a {
56
- position: relative;
57
- overflow: hidden;
58
- display: block;
59
- }
60
-
61
- img {
62
- @include transition(all 0.2s ease);
63
- @include transform(scale(1));
64
- }
65
- }
66
-
67
- .neklo-instagram-over {
68
- position: absolute;
69
- left: 0;
70
- top: 0;
71
- bottom: 0;
72
- right: 0;
73
- margin: auto;
74
- background: #000000;
75
- @include opacity(0.3);
76
- @include transition(all 0.2s ease);
77
- z-index: 10;
78
  }
1
+ @import "mixin/mixin";
2
+ @import "compass/css3";
3
+
4
+ .neklo-instagram-title {
5
+ text-transform: uppercase;
6
+ font-size: 18px;
7
+ font-weight: bold;
8
+ color: #000000;
9
+ text-align: center;
10
+ margin-bottom: 10px;
11
+
12
+ @include breakpointmedia(768, 'max-width') {
13
+ font-size: 16px;
14
+ }
15
+ }
16
+
17
+ .neklo-instagram-description {
18
+ font-size: 14px;
19
+ color: #000000;
20
+ text-align: center;
21
+ margin-bottom: 10px;
22
+
23
+ @include breakpointmedia(768, 'max-width') {
24
+ font-size: 12px;
25
+ }
26
+ }
27
+
28
+ .neklo-instagram-list {
29
+ @include clearfix();
30
+ margin: 20px auto;
31
+ width: 80%;
32
+ text-align: center;
33
+ font-size: 0;
34
+
35
+ @include breakpointmedia(768, 'max-width') {
36
+ width: 95%;
37
+ }
38
+
39
+ li {
40
+ display: inline-block;
41
+ vertical-align: top;
42
+ @include transition(all 0.2s ease);
43
+ margin: 0 2px 2px 0;
44
+
45
+ &:hover {
46
+ .neklo-instagram-over {
47
+ @include border-radius(50%);
48
+ @include transform(scale(0));
49
+ }
50
+
51
+ img { @include transform(scale(1.2)); }
52
+ }
53
+ }
54
+
55
+ a {
56
+ position: relative;
57
+ overflow: hidden;
58
+ display: block;
59
+ }
60
+
61
+ img {
62
+ @include transition(all 0.2s ease);
63
+ @include transform(scale(1));
64
+ }
65
+ }
66
+
67
+ .neklo-instagram-over {
68
+ position: absolute;
69
+ left: 0;
70
+ top: 0;
71
+ bottom: 0;
72
+ right: 0;
73
+ margin: auto;
74
+ background: #000000;
75
+ @include opacity(0.3);
76
+ @include transition(all 0.2s ease);
77
+ z-index: 10;
78
  }