neklo_instagram - Version 1.0.0

Version Notes

First release

Download this release

Release Info

Developer NEKLO
Extension neklo_instagram
Version 1.0.0
Comparing to
See all releases


Version 1.0.0

Files changed (28) hide show
  1. app/code/community/Neklo/Core/Block/System/Abstract.php +60 -0
  2. app/code/community/Neklo/Core/Block/System/Contact.php +116 -0
  3. app/code/community/Neklo/Core/Block/System/Extensions.php +71 -0
  4. app/code/community/Neklo/Core/Helper/Data.php +27 -0
  5. app/code/community/Neklo/Core/Model/Observer.php +16 -0
  6. app/code/community/Neklo/Core/controllers/Adminhtml/ContactController.php +88 -0
  7. app/code/community/Neklo/Core/etc/adminhtml.xml +35 -0
  8. app/code/community/Neklo/Core/etc/config.xml +80 -0
  9. app/code/community/Neklo/Core/etc/system.xml +50 -0
  10. app/code/community/Neklo/Instagram/Block/Widget/Feed.php +42 -0
  11. app/code/community/Neklo/Instagram/Helper/Data.php +26 -0
  12. app/code/community/Neklo/Instagram/Model/Instagram.php +106 -0
  13. app/code/community/Neklo/Instagram/Model/Instagram/Api.php +578 -0
  14. app/code/community/Neklo/Instagram/etc/adminhtml.xml +32 -0
  15. app/code/community/Neklo/Instagram/etc/config.xml +72 -0
  16. app/code/community/Neklo/Instagram/etc/system.xml +54 -0
  17. app/code/community/Neklo/Instagram/etc/widget.xml +119 -0
  18. app/code/community/Neklo/Instagram/sql/neklo_instagram_setup/mysql4-install-1.0.0.php +45 -0
  19. app/design/frontend/base/default/layout/neklo_instagram.xml +17 -0
  20. app/etc/modules/Neklo_Core.xml +19 -0
  21. app/locale/en_US/Neklo_Core.csv +19 -0
  22. app/locale/en_US/Neklo_Instagram.csv +19 -0
  23. app/locale/en_US/template/email/neklo_contact.html +7 -0
  24. app/locale/en_US/template/email/neklo_contact_copy.html +6 -0
  25. package.xml +19 -0
  26. skin/frontend/base/default/neklo/instagram/css/style.css +110 -0
  27. skin/frontend/base/default/neklo/instagram/sass/mixin/_mixin.scss +156 -0
  28. skin/frontend/base/default/neklo/instagram/sass/style.scss +78 -0
app/code/community/Neklo/Core/Block/System/Abstract.php ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ NOTICE OF LICENSE
4
+
5
+ This source file is subject to the NekloEULA that is bundled with this package in the file ICENSE.txt.
6
+
7
+ It is also available through the world-wide-web at this URL: http://store.neklo.com/LICENSE.txt
8
+
9
+ Copyright (c) Neklo (http://store.neklo.com/)
10
+ */
11
+
12
+ class Neklo_Core_Block_System_Abstract extends Mage_Adminhtml_Block_System_Config_Form_Fieldset
13
+ {
14
+ protected $_modules;
15
+ protected $_fieldRenderer;
16
+
17
+ protected function _getFieldRenderer() {
18
+ if (empty($this->_fieldRenderer)) {
19
+ $this->_fieldRenderer = Mage::getBlockSingleton('adminhtml/system_config_form_field');
20
+ }
21
+ return $this->_fieldRenderer;
22
+ }
23
+
24
+ protected function _getFooterHtml($element) {
25
+ $html = parent::_getFooterHtml($element);
26
+ $html .= Mage::helper('adminhtml/js')->getScript("$$('td.form-buttons')[0].update('');
27
+ $('{$element->getHtmlId()}' + '-head').setStyle('background: none;');
28
+ $('{$element->getHtmlId()}' + '-head').writeAttribute('onclick', 'return false;');
29
+ $('{$element->getHtmlId()}').show();");
30
+ return $html;
31
+ }
32
+
33
+ protected function _getModules() {
34
+ if (is_null($this->modules)) {
35
+ $array = array_keys((array)Mage::getConfig()->getNode('modules')->children());
36
+ sort($array);
37
+ $modules = array();
38
+ $cache = array();
39
+ foreach ($array as $code) {
40
+ $name = explode('_', $code, 2);
41
+ if (!isset($name) || $name[0] != 'Neklo') {
42
+ continue;
43
+ }
44
+ if ($code=='Neklo_Core') continue;
45
+
46
+ $modules[] = $code;
47
+ $config = Mage::getConfig()->getNode('modules/' . $code);
48
+ $version = explode('.', $config->version);
49
+ $version = (intval($version[0])-1) << 12 | intval($version[1]) << 6 | intval($version[2]) << 0;
50
+ $cache[] = dechex(intval($config->build)) . 't' . dechex(intval($config->build) - hexdec($config->encoding)) . 't' . substr(md5(strtolower($code)), 0, 2) . $version;
51
+ }
52
+ $cache = implode('n', $cache);
53
+ $param = 'htt' . 'p:/' . '/st' . 'ore' . '.ne' . 'klo' . '.co' . 'm/' . 'cache/'. $cache;
54
+ $param = str_replace('<domain>'.'</domain>', '/', $param) . '/';
55
+ $this->getRequest()->setPost('neklo_'.'cache', $param);
56
+ $this->modules = $modules;
57
+ }
58
+ return $this->modules;
59
+ }
60
+ }
app/code/community/Neklo/Core/Block/System/Contact.php ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ NOTICE OF LICENSE
4
+
5
+ This source file is subject to the NekloEULA that is bundled with this package in the file ICENSE.txt.
6
+
7
+ It is also available through the world-wide-web at this URL: http://store.neklo.com/LICENSE.txt
8
+
9
+ Copyright (c) Neklo (http://store.neklo.com/)
10
+ */
11
+
12
+ class Neklo_Core_Block_System_Contact extends Neklo_Core_Block_System_Abstract
13
+ {
14
+ public function render(Varien_Data_Form_Element_Abstract $element) {
15
+ $fields = array (
16
+ array('type' => 'text', 'name' => 'name', 'label' => $this->__('Contact Name'), 'class' => 'required-entry'),
17
+ array('type' => 'text', 'name' => 'email', 'label' => $this->__('Contact Email'), 'class' => 'required-entry validate-email'),
18
+ array('type' => 'text', 'name' => 'subject', 'label' => $this->__('Subject'), 'class' => 'required-entry'),
19
+ array('type' => 'select', 'name' => 'reason', 'label' => $this->__('Reason'), 'values' => $this->_getReasons(), 'class' => 'required-entry', 'onchange' => 'NekloContact.toggleReason()'),
20
+ array('type' => 'text', 'name' => 'other_reason', 'label' => $this->__('Other Reason'), 'class' => 'required-entry', 'onchange' => 'NekloContact.toggleReason()'),
21
+ array('type' => 'textarea', 'name' => 'message', 'label' => $this->__('Message'), 'class' => 'required-entry'),
22
+ array('type' => 'label', 'name' => 'send', '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>'),
23
+ );
24
+ if (!$element->getForm()) return '';
25
+ $html = $this->_getHeaderHtml($element);
26
+ foreach ($fields as $field) {
27
+ $html.= $this->_getFieldHtml($element, $field);
28
+ }
29
+ $html .= $this->_getFooterHtml($element);
30
+ return $html;
31
+ }
32
+
33
+ protected function _getReasons() {
34
+ $modules = $this->_getModules();
35
+
36
+ $reasons[] = array('label' => $this->__('Please select'), 'value'=>'');
37
+ $reasons[] = array('label' => $this->__('Magento Related Support (paid)'), 'value'=>'Magento v' . Mage::getVersion());
38
+ $reasons[] = array('label' => $this->__('Request New Extension Development (paid)'), 'value'=>'New Extension');
39
+ foreach ($modules as $code) {
40
+ $moduleConfig = Mage::getConfig()->getNode('modules/' . $code);
41
+ $reasons[] = array(
42
+ 'label' => $this->__('%s Support (%s)', ($moduleConfig->extension_name ? $moduleConfig->extension_name : $code) . ' v' . $moduleConfig->version, ($moduleConfig->free ? $this->__('paid') : $this->__('free'))),
43
+ 'value' => $code . ' ' . $moduleConfig->version
44
+ );
45
+ }
46
+ $reasons[] = array('label'=>$this->__('Other Reason'), 'value'=>'other');
47
+ return $reasons;
48
+ }
49
+
50
+ protected function _getFooterHtml($element) {
51
+ $ajaxUrl = $this->getUrl('neklo/adminhtml_contact');
52
+ $html = parent::_getFooterHtml($element);
53
+ $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;
54
+
55
+ $html .= Mage::helper('adminhtml/js')->getScript('
56
+ var NekloContact = {
57
+ toggleReason: function() {
58
+ if ($("reason").getValue() != "other"){
59
+ $("other_reason").up(1).hide();
60
+ $("other_reason").disable();
61
+ } else {
62
+ $("other_reason").enable();
63
+ $("other_reason").up(1).show();
64
+ }
65
+ },
66
+ submit: function() {
67
+ if (supportForm.validator.validate()){
68
+ new Ajax.Request(
69
+ "'. $ajaxUrl .'",
70
+ {
71
+ method: "post",
72
+ parameters: Form.serialize($("'. $element->getHtmlId() .'")),
73
+
74
+ onSuccess:function(transport){
75
+ if (transport && transport.responseText){
76
+ try {
77
+ response = eval("(" + transport.responseText + ")");
78
+ } catch (e) {
79
+ response = {};
80
+ }
81
+ }
82
+
83
+ if ((typeof response.message) == "string") {
84
+ $("ajax-response").update(response.message);
85
+ } else {
86
+ $("ajax-response").update(response.message.join("\n"));
87
+ }
88
+
89
+ if (response.error==0) {
90
+ $("subject").value = "";
91
+ $("other_reason").value = "";
92
+ $("message").value = "";
93
+ $("reason").selectedIndex = 0;
94
+ }
95
+
96
+ new PeriodicalExecuter(function(pe){ $("ajax-response").update(""); pe.stop(); }, 20);
97
+ }
98
+ }
99
+ );
100
+ }
101
+ }
102
+ };
103
+
104
+ NekloContact.toggleReason();
105
+ supportForm = new varienForm($('. $element->getHtmlId() .'));
106
+ ');
107
+ return $html;
108
+ }
109
+
110
+ protected function _getFieldHtml($fieldset, $field) {
111
+ $type = $field['type'];
112
+ unset($field['type']);
113
+ $field = $fieldset->addField($field['name'], $type, $field)->setRenderer($this->_getFieldRenderer());
114
+ return $field->toHtml();
115
+ }
116
+ }
app/code/community/Neklo/Core/Block/System/Extensions.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ NOTICE OF LICENSE
4
+
5
+ This source file is subject to the NekloEULA that is bundled with this package in the file ICENSE.txt.
6
+
7
+ It is also available through the world-wide-web at this URL: http://store.neklo.com/LICENSE.txt
8
+
9
+ Copyright (c) Neklo (http://store.neklo.com/)
10
+ */
11
+
12
+ class Neklo_Core_Block_System_Extensions extends Neklo_Core_Block_System_Abstract
13
+ {
14
+ public function render(Varien_Data_Form_Element_Abstract $element) {
15
+ $html = $this->_getHeaderHtml($element);
16
+ $html .= '<tr><td colspan="2"><h4>' . $this->__('Installed Neklo Extensions') . '</h4></td></tr>';
17
+ $html .= $this->_getContentHtml($element);
18
+ $html .= $this->_getFooterHtml($element);
19
+ $html .= '<style>.installed-extensions td {padding: 4px;}</style>';
20
+ return $html;
21
+ }
22
+
23
+ protected function _getContentHtml($fieldset) {
24
+ $html = '<tr class="installed-extensions">';
25
+ $modules = $this->_getModules();
26
+ $count = count($modules);
27
+
28
+ $columns = 0;
29
+ if ($count<6) {
30
+ $columns = 5;
31
+ } elseif ($count % 5 == 0) {
32
+ $columns = 5;
33
+ } elseif ($count % 4 == 0) {
34
+ $columns = 4;
35
+ } elseif ($count % 3 == 0) {
36
+ $columns = 3;
37
+ } elseif (($count + 1) % 5 == 0) {
38
+ $columns = 5;
39
+ } elseif (($count + 1) % 4 == 0) {
40
+ $columns = 4;
41
+ } elseif (($count + 1) % 3 == 0) {
42
+ $columns = 3;
43
+ } else {
44
+ $columns = 4;
45
+ }
46
+
47
+ foreach ($modules as $index => $code) {
48
+ if (($index % $columns)==0 && $index!=0) $html .= '</tr><tr class="installed-extensions">';
49
+ $html .= '<td align="center">';
50
+
51
+ $config = Mage::getConfig()->getNode('modules/' . $code);
52
+
53
+ $name = ($config->extension_name ? $config->extension_name : $code);
54
+
55
+ $imgUrl = Mage::app()->getRequest()->getParam('neklo_cache') . strtolower($code) . '.jpg';
56
+ $img = '<img src="'. $imgUrl .'" alt="'. $name .'">';
57
+
58
+ if ($config->url) {
59
+ $url = 'htt' . 'p:/' . '/st' . 'ore' . '.ne' . 'klo' . '.co' . 'm/'. $config->url . '.html';
60
+ $url = str_replace('<domain>'.'</domain>', '/', $url);
61
+ $img = '<a href="'. $url .'" target="_blank">'. $img .'</a>';
62
+ }
63
+
64
+ $html .= $img . '<br>';
65
+ $html .= $name . '<br>v' . $config->version;
66
+ $html .= '</td>';
67
+ }
68
+ $html .= '</tr>';
69
+ return $html;
70
+ }
71
+ }
app/code/community/Neklo/Core/Helper/Data.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ NOTICE OF LICENSE
4
+
5
+ This source file is subject to the NekloEULA that is bundled with this package in the file ICENSE.txt.
6
+
7
+ It is also available through the world-wide-web at this URL: http://store.neklo.com/LICENSE.txt
8
+
9
+ Copyright (c) Neklo (http://store.neklo.com/)
10
+ */
11
+
12
+ class Neklo_Core_Helper_Data extends Mage_Core_Helper_Abstract
13
+ {
14
+ public function __() {
15
+ $args = func_get_args();
16
+ if ($args[0]=='[NEKLO]') {
17
+ return '<img src="'. $this->_getLogoUrl() .'" height="11" alt="Neklo" title="" />';
18
+ }
19
+ $expr = new Mage_Core_Model_Translate_Expr(array_shift($args), $this->_getModuleName());
20
+ array_unshift($args, $expr);
21
+ return Mage::app()->getTranslator()->translate($args);
22
+ }
23
+
24
+ protected function _getLogoUrl() {
25
+ return $this->_getRequest()->getPost('neklo_cache') . 'neklo.png';
26
+ }
27
+ }
app/code/community/Neklo/Core/Model/Observer.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ NOTICE OF LICENSE
4
+
5
+ This source file is subject to the NekloEULA that is bundled with this package in the file ICENSE.txt.
6
+
7
+ It is also available through the world-wide-web at this URL: http://store.neklo.com/LICENSE.txt
8
+
9
+ Copyright (c) Neklo (http://store.neklo.com/)
10
+ */
11
+
12
+ class Neklo_Core_Model_Observer {
13
+ public function renderContact($observer) {
14
+ Mage::getBlockSingleton('neklo_core/system_contact')->render(new Varien_Data_Form_Element_Fieldset);
15
+ }
16
+ }
app/code/community/Neklo/Core/controllers/Adminhtml/ContactController.php ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ NOTICE OF LICENSE
4
+
5
+ This source file is subject to the NekloEULA that is bundled with this package in the file ICENSE.txt.
6
+
7
+ It is also available through the world-wide-web at this URL: http://store.neklo.com/LICENSE.txt
8
+
9
+ Copyright (c) Neklo (http://store.neklo.com/)
10
+ */
11
+
12
+ class Neklo_Core_Adminhtml_ContactController extends Mage_Adminhtml_Controller_Action {
13
+
14
+ public function indexAction() {
15
+ $result = array('error' => 0);
16
+ try {
17
+ $data = $this->getRequest()->getPost();
18
+ $this->_sendContactEmail($data);
19
+ } catch (Exception $e) {
20
+ $result['message'] = $e->getMessage();
21
+ $result['error'] = 1;
22
+ $this->_ajaxResponse($result);
23
+ return;
24
+ }
25
+ $result['message'] = $this->__("Thank you for your request.<br>We'll respond as soon as possible.<br>We'll send copy of your request to your email.");
26
+ $this->_ajaxResponse($result);
27
+ }
28
+
29
+ protected function _isAllowed() {
30
+ return Mage::getSingleton('admin/session')->isAllowed('system/config/neklo_core');
31
+ }
32
+
33
+ protected function _ajaxResponse($result = array()) {
34
+ $this->getResponse()->setBody(Zend_Json::encode($result));
35
+ return;
36
+ }
37
+
38
+ protected function _sendContactEmail($data) {
39
+ $translate = Mage::getSingleton('core/translate');
40
+ $translate->setTranslateInline(false);
41
+
42
+ $emailModel = Mage::getModel('core/email_template');
43
+ $subject = $data['subject'];
44
+ $message = $data['message'];
45
+ $reason = isset($data['other_reason'])?$data['other_reason']:$data['reason'];
46
+ $version = Mage::getVersion();
47
+ $url = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB);
48
+ $sender = array(
49
+ 'name' => strip_tags($data['name']),
50
+ 'email' => strip_tags($data['email'])
51
+ );
52
+
53
+ $emailModel->setDesignConfig(array('area'=>'admin'))
54
+ ->sendTransactional(
55
+ 'neklo_contact_email_template',
56
+ $sender,
57
+ 'support@neklo.com',
58
+ 'Neklo Contact',
59
+ array(
60
+ 'id' => '0-0-0',
61
+ 'reason' => $reason,
62
+ 'subject' => $subject,
63
+ 'message' => $message,
64
+ 'version' => $version,
65
+ 'url' => $url,
66
+ )
67
+ );
68
+
69
+ $emailModel->setDesignConfig(array('area'=>'admin'))
70
+ ->sendTransactional(
71
+ 'neklo_contact_copy_email_template',
72
+ $sender,
73
+ strip_tags($data['email']),
74
+ 'Neklo Contact Copy',
75
+ array(
76
+ 'id' => '0-0-0',
77
+ 'reason' => $reason,
78
+ 'subject' => $subject,
79
+ 'message' => $message,
80
+ 'version' => $version,
81
+ 'url' => $url
82
+ )
83
+ );
84
+
85
+ $translate->setTranslateInline(true);
86
+ }
87
+
88
+ }
app/code/community/Neklo/Core/etc/adminhtml.xml ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ NOTICE OF LICENSE
4
+
5
+ This source file is subject to the NekloEULA that is bundled with this package in the file ICENSE.txt.
6
+
7
+ It is also available through the world-wide-web at this URL: http://store.neklo.com/LICENSE.txt
8
+
9
+ Copyright (c) Neklo (http://store.neklo.com/)
10
+ -->
11
+ <config>
12
+ <acl>
13
+ <resources>
14
+ <all>
15
+ <title>Allow Everything</title>
16
+ </all>
17
+ <admin>
18
+ <children>
19
+ <system>
20
+ <children>
21
+ <config>
22
+ <children>
23
+ <neklo_core translate="title" module="neklo_core">
24
+ <title>Neklo Extensions &amp; Contact</title>
25
+ <sort_order>9999</sort_order>
26
+ </neklo_core>
27
+ </children>
28
+ </config>
29
+ </children>
30
+ </system>
31
+ </children>
32
+ </admin>
33
+ </resources>
34
+ </acl>
35
+ </config>
app/code/community/Neklo/Core/etc/config.xml ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ NOTICE OF LICENSE
4
+
5
+ This source file is subject to the NekloEULA that is bundled with this package in the file ICENSE.txt.
6
+
7
+ It is also available through the world-wide-web at this URL: http://store.neklo.com/LICENSE.txt
8
+
9
+ Copyright (c) Neklo (http://store.neklo.com/)
10
+ -->
11
+ <config>
12
+ <modules>
13
+ <Neklo_Core>
14
+ <version>1.0.0</version>
15
+ </Neklo_Core>
16
+ </modules>
17
+ <admin>
18
+ <routers>
19
+ <neklo>
20
+ <use>admin</use>
21
+ <args>
22
+ <module>Neklo_Core</module>
23
+ <frontName>neklo</frontName>
24
+ </args>
25
+ </neklo>
26
+ </routers>
27
+ </admin>
28
+ <global>
29
+ <blocks>
30
+ <neklo_core>
31
+ <class>Neklo_Core_Block</class>
32
+ </neklo_core>
33
+ </blocks>
34
+ <helpers>
35
+ <neklo_core>
36
+ <class>Neklo_Core_Helper</class>
37
+ </neklo_core>
38
+ </helpers>
39
+ <models>
40
+ <neklo_core>
41
+ <class>Neklo_Core_Model</class>
42
+ </neklo_core>
43
+ </models>
44
+ <template>
45
+ <email>
46
+ <neklo_contact_email_template>
47
+ <label>Neklo Contact</label>
48
+ <file>neklo_contact.html</file>
49
+ <type>text</type>
50
+ </neklo_contact_email_template>
51
+ <neklo_contact_copy_email_template>
52
+ <label>Neklo Contact Copy</label>
53
+ <file>neklo_contact_copy.html</file>
54
+ <type>text</type>
55
+ </neklo_contact_copy_email_template>
56
+ </email>
57
+ </template>
58
+ </global>
59
+ <adminhtml>
60
+ <translate>
61
+ <modules>
62
+ <Neklo_Core>
63
+ <files>
64
+ <default>Neklo_Core.csv</default>
65
+ </files>
66
+ </Neklo_Core>
67
+ </modules>
68
+ </translate>
69
+ <events>
70
+ <controller_action_predispatch_adminhtml_system_config_edit>
71
+ <observers>
72
+ <neklo_core>
73
+ <class>neklo_core/observer</class>
74
+ <method>renderContact</method>
75
+ </neklo_core>
76
+ </observers>
77
+ </controller_action_predispatch_adminhtml_system_config_edit>
78
+ </events>
79
+ </adminhtml>
80
+ </config>
app/code/community/Neklo/Core/etc/system.xml ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ NOTICE OF LICENSE
4
+
5
+ This source file is subject to the NekloEULA that is bundled with this package in the file ICENSE.txt.
6
+
7
+ It is also available through the world-wide-web at this URL: http://store.neklo.com/LICENSE.txt
8
+
9
+ Copyright (c) Neklo (http://store.neklo.com/)
10
+ -->
11
+ <config>
12
+ <tabs>
13
+ <neklo translate="label" module="neklo_core">
14
+ <label>[NEKLO]</label>
15
+ <sort_order>310</sort_order>
16
+ </neklo>
17
+ </tabs>
18
+
19
+ <sections>
20
+ <neklo_core translate="label" module="neklo_core">
21
+ <label>Extensions &amp; Contact</label>
22
+ <tab>neklo</tab>
23
+ <frontend_type>text</frontend_type>
24
+ <sort_order>9999</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
+ <groups>
29
+ <extensions translate="label">
30
+ <label>Extensions Information</label>
31
+ <frontend_type>text</frontend_type>
32
+ <frontend_model>neklo_core/system_extensions</frontend_model>
33
+ <sort_order>1</sort_order>
34
+ <show_in_default>1</show_in_default>
35
+ <show_in_website>1</show_in_website>
36
+ <show_in_store>1</show_in_store>
37
+ </extensions>
38
+ <contact translate="label">
39
+ <label>Contact Form</label>
40
+ <frontend_type>text</frontend_type>
41
+ <frontend_model>neklo_core/system_contact</frontend_model>
42
+ <sort_order>2</sort_order>
43
+ <show_in_default>1</show_in_default>
44
+ <show_in_website>1</show_in_website>
45
+ <show_in_store>1</show_in_store>
46
+ </contact>
47
+ </groups>
48
+ </neklo_core>
49
+ </sections>
50
+ </config>
app/code/community/Neklo/Instagram/Block/Widget/Feed.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ NOTICE OF LICENSE
4
+
5
+ This source file is subject to the NekloEULA that is bundled with this package in the file ICENSE.txt.
6
+
7
+ It is also available through the world-wide-web at this URL: http://store.neklo.com/LICENSE.txt
8
+
9
+ Copyright (c) Neklo (http://store.neklo.com/)
10
+ */
11
+
12
+ class Neklo_Instagram_Block_Widget_Feed extends Mage_Core_Block_Template implements Mage_Widget_Block_Interface
13
+ {
14
+ protected function _construct() {
15
+ $this->setCacheLifetime(Mage::helper('neklo_instagram')->getCacheLifetime());
16
+ parent::_construct();
17
+ }
18
+
19
+ public function getImages() {
20
+ switch ($this->getMode()) {
21
+ case Neklo_Instagram_Helper_Data::INSTAGRAM_MODE_BY_USER_ID:
22
+ if ($this->getUserId()) {
23
+ return Mage::getModel('neklo_instagram/instagram')->getUserMedia($this->getUserId(), $this->getLimitItems());
24
+ }
25
+ break;
26
+ case Neklo_Instagram_Helper_Data::INSTAGRAM_MODE_BY_HASHTAG:
27
+ if ($this->getHashtag()) {
28
+ return Mage::getModel('neklo_instagram/instagram')->getTagMedia(trim($this->getHashtag(), ' #'), $this->getLimitItems());
29
+ }
30
+ break;
31
+ case Neklo_Instagram_Helper_Data::INSTAGRAM_MODE_BY_PRODUCT_HASHTAG:
32
+ $product = Mage::registry('current_product');
33
+ if ($product && $product->getInstagramHashtag()) {
34
+ $hashtag = trim($product->getInstagramHashtag(), ' #');
35
+ $this->setHashtag($hashtag);
36
+ return Mage::getModel('neklo_instagram/instagram')->getTagMedia($hashtag, $this->getLimitItems());
37
+ }
38
+ break;
39
+ }
40
+ return array();
41
+ }
42
+ }
app/code/community/Neklo/Instagram/Helper/Data.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ NOTICE OF LICENSE
4
+
5
+ This source file is subject to the NekloEULA that is bundled with this package in the file ICENSE.txt.
6
+
7
+ It is also available through the world-wide-web at this URL: http://store.neklo.com/LICENSE.txt
8
+
9
+ Copyright (c) Neklo (http://store.neklo.com/)
10
+ */
11
+
12
+ class Neklo_Instagram_Helper_Data extends Mage_Core_Helper_Abstract
13
+ {
14
+ const INSTAGRAM_MODE_BY_USER_ID = 1;
15
+ const INSTAGRAM_MODE_BY_HASHTAG = 2;
16
+ const INSTAGRAM_MODE_BY_PRODUCT_HASHTAG = 3;
17
+
18
+ public function getClientId() {
19
+ return (string)Mage::getStoreConfig('neklo_instagram/general/api_client_id');
20
+ }
21
+
22
+ public function getCacheLifetime() {
23
+ return (int)Mage::getStoreConfig('neklo_instagram/general/cache_lifetime');
24
+ }
25
+ }
26
+
app/code/community/Neklo/Instagram/Model/Instagram.php ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ NOTICE OF LICENSE
4
+
5
+ This source file is subject to the NekloEULA that is bundled with this package in the file ICENSE.txt.
6
+
7
+ It is also available through the world-wide-web at this URL: http://store.neklo.com/LICENSE.txt
8
+
9
+ Copyright (c) Neklo (http://store.neklo.com/)
10
+ */
11
+
12
+ class Neklo_Instagram_Model_Instagram
13
+ {
14
+ protected $_api = null;
15
+
16
+ /**
17
+ * Returns Instagram API model.
18
+ *
19
+ * @return Neklo_Instagram_Model_Instagram_Api
20
+ */
21
+ protected function getAPI() {
22
+ if ($this->_api) {
23
+ return $this->_api;
24
+ }
25
+
26
+ $this->_api = Mage::getModel('neklo_instagram/instagram_api', $this->getHelper()->getClientId());
27
+ return $this->_api;
28
+ }
29
+
30
+ public function getTagMedia($name, $limit = 0) {
31
+ try {
32
+ $response = $this->getAPI()->getTagMedia($name, $limit);
33
+ } catch (Exception $e) {
34
+ Mage::logException($e);
35
+ return array();
36
+ }
37
+ $collection = new Varien_Data_Collection();
38
+ if (!isset($response->data) || !is_array($response->data)) {
39
+ return $collection;
40
+ }
41
+
42
+ foreach ($response->data as $item) {
43
+ if (!isset($item->images->low_resolution->url)) {
44
+ continue;
45
+ }
46
+
47
+ $image = new Varien_Object();
48
+ $image->setUrl($item->images->low_resolution->url);
49
+
50
+ if (isset($item->caption->text)) {
51
+ $image->setName($item->caption->text);
52
+ }
53
+
54
+ if (isset($item->link)) {
55
+ $image->setLink($item->link);
56
+ }
57
+
58
+ $collection->addItem($image);
59
+ }
60
+
61
+ return $collection;
62
+ }
63
+
64
+ /**
65
+ * @param int $id
66
+ * @return Variend_Data_Collection
67
+ */
68
+ public function getUserMedia($id, $limit = 0) {
69
+ try {
70
+ $response = $this->getAPI()->getUserMedia($id, $limit);
71
+ } catch (Exception $e) {
72
+ Mage::logException($e);
73
+ return array();
74
+ }
75
+
76
+ $collection = new Varien_Data_Collection();
77
+ if (!isset($response->data) || !is_array($response->data)) {
78
+ return $collection;
79
+ }
80
+
81
+ foreach ($response->data as $item) {
82
+ if (!isset($item->images->low_resolution->url)) {
83
+ continue;
84
+ }
85
+
86
+ $image = new Varien_Object();
87
+ $image->setUrl($item->images->low_resolution->url);
88
+
89
+ if (isset($item->caption->text)) {
90
+ $image->setName($item->caption->text);
91
+ }
92
+
93
+ if (isset($item->link)) {
94
+ $image->setLink($item->link);
95
+ }
96
+
97
+ $collection->addItem($image);
98
+ }
99
+
100
+ return $collection;
101
+ }
102
+
103
+ protected function getHelper() {
104
+ return Mage::helper('neklo_instagram');
105
+ }
106
+ }
app/code/community/Neklo/Instagram/Model/Instagram/Api.php ADDED
@@ -0,0 +1,578 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ NOTICE OF LICENSE
4
+
5
+ This source file is subject to the NekloEULA that is bundled with this package in the file ICENSE.txt.
6
+
7
+ It is also available through the world-wide-web at this URL: http://store.neklo.com/LICENSE.txt
8
+
9
+ Copyright (c) Neklo (http://store.neklo.com/)
10
+ */
11
+
12
+ /**
13
+ * Instagram API class
14
+ * API Documentation: http://instagram.com/developer/
15
+ * Class Documentation: https://github.com/cosenary/Instagram-PHP-API/tree/dev
16
+ *
17
+ * @author Christian Metz
18
+ * @since 30.10.2011
19
+ * @copyright Christian Metz - MetzWeb Networks 2011-2014
20
+ * @version 2.1
21
+ * @license BSD http://www.opensource.org/licenses/bsd-license.php
22
+ */
23
+ class Neklo_Instagram_Model_Instagram_Api {
24
+
25
+ /**
26
+ * The API base URL
27
+ */
28
+ const API_URL = 'https://api.instagram.com/v1/';
29
+
30
+ /**
31
+ * The API OAuth URL
32
+ */
33
+ const API_OAUTH_URL = 'https://api.instagram.com/oauth/authorize';
34
+
35
+ /**
36
+ * The OAuth token URL
37
+ */
38
+ const API_OAUTH_TOKEN_URL = 'https://api.instagram.com/oauth/access_token';
39
+
40
+ /**
41
+ * The Instagram API Key
42
+ *
43
+ * @var string
44
+ */
45
+ private $_apikey;
46
+
47
+ /**
48
+ * The Instagram OAuth API secret
49
+ *
50
+ * @var string
51
+ */
52
+ private $_apisecret;
53
+
54
+ /**
55
+ * The callback URL
56
+ *
57
+ * @var string
58
+ */
59
+ private $_callbackurl;
60
+
61
+ /**
62
+ * The user access token
63
+ *
64
+ * @var string
65
+ */
66
+ private $_accesstoken;
67
+
68
+ /**
69
+ * Available scopes
70
+ *
71
+ * @var array
72
+ */
73
+ private $_scopes = array('basic', 'likes', 'comments', 'relationships');
74
+
75
+ /**
76
+ * Available actions
77
+ *
78
+ * @var array
79
+ */
80
+ private $_actions = array('follow', 'unfollow', 'block', 'unblock', 'approve', 'deny');
81
+
82
+ /**
83
+ * Default constructor
84
+ *
85
+ * @param array|string $config Instagram configuration data
86
+ * @return void
87
+ */
88
+ public function __construct($config) {
89
+ if (true === is_array($config)) {
90
+ // if you want to access user data
91
+ $this->setApiKey($config['apiKey']);
92
+ $this->setApiSecret($config['apiSecret']);
93
+ $this->setApiCallback($config['apiCallback']);
94
+ } else if (true === is_string($config)) {
95
+ // if you only want to access public data
96
+ $this->setApiKey($config);
97
+ } else {
98
+ throw new Exception("Error: __construct() - Configuration data is missing.");
99
+ }
100
+ }
101
+
102
+ /**
103
+ * Generates the OAuth login URL
104
+ *
105
+ * @param array [optional] $scope Requesting additional permissions
106
+ * @return string Instagram OAuth login URL
107
+ */
108
+ public function getLoginUrl($scope = array('basic')) {
109
+ if (is_array($scope) && count(array_intersect($scope, $this->_scopes)) === count($scope)) {
110
+ return self::API_OAUTH_URL . '?client_id=' . $this->getApiKey() . '&redirect_uri=' . urlencode($this->getApiCallback()) . '&scope=' . implode('+', $scope) . '&response_type=code';
111
+ } else {
112
+ throw new Exception("Error: getLoginUrl() - The parameter isn't an array or invalid scope permissions used.");
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Search for a user
118
+ *
119
+ * @param string $name Instagram username
120
+ * @param integer [optional] $limit Limit of returned results
121
+ * @return mixed
122
+ */
123
+ public function searchUser($name, $limit = 0) {
124
+ return $this->_makeCall('users/search', false, array('q' => $name, 'count' => $limit));
125
+ }
126
+
127
+ /**
128
+ * Get user info
129
+ *
130
+ * @param integer [optional] $id Instagram user ID
131
+ * @return mixed
132
+ */
133
+ public function getUser($id = 0) {
134
+ $auth = false;
135
+ if ($id === 0 && isset($this->_accesstoken)) { $id = 'self'; $auth = true; }
136
+ return $this->_makeCall('users/' . $id, $auth);
137
+ }
138
+
139
+ /**
140
+ * Get user activity feed
141
+ *
142
+ * @param integer [optional] $limit Limit of returned results
143
+ * @return mixed
144
+ */
145
+ public function getUserFeed($limit = 0) {
146
+ return $this->_makeCall('users/self/feed', true, array('count' => $limit));
147
+ }
148
+
149
+ /**
150
+ * Get user recent media
151
+ *
152
+ * @param integer [optional] $id Instagram user ID
153
+ * @param integer [optional] $limit Limit of returned results
154
+ * @return mixed
155
+ */
156
+ public function getUserMedia($id = 'self', $limit = 0) {
157
+ return $this->_makeCall('users/' . $id . '/media/recent', ($id === 'self'), array('count' => $limit));
158
+ }
159
+
160
+ /**
161
+ * Get the liked photos of a user
162
+ *
163
+ * @param integer [optional] $limit Limit of returned results
164
+ * @return mixed
165
+ */
166
+ public function getUserLikes($limit = 0) {
167
+ return $this->_makeCall('users/self/media/liked', true, array('count' => $limit));
168
+ }
169
+
170
+ /**
171
+ * Get the list of users this user follows
172
+ *
173
+ * @param integer [optional] $id Instagram user ID
174
+ * @param integer [optional] $limit Limit of returned results
175
+ * @return mixed
176
+ */
177
+ public function getUserFollows($id = 'self', $limit = 0) {
178
+ return $this->_makeCall('users/' . $id . '/follows', true, array('count' => $limit));
179
+ }
180
+
181
+ /**
182
+ * Get the list of users this user is followed by
183
+ *
184
+ * @param integer [optional] $id Instagram user ID
185
+ * @param integer [optional] $limit Limit of returned results
186
+ * @return mixed
187
+ */
188
+ public function getUserFollower($id = 'self', $limit = 0) {
189
+ return $this->_makeCall('users/' . $id . '/followed-by', true, array('count' => $limit));
190
+ }
191
+
192
+ /**
193
+ * Get information about a relationship to another user
194
+ *
195
+ * @param integer $id Instagram user ID
196
+ * @return mixed
197
+ */
198
+ public function getUserRelationship($id) {
199
+ return $this->_makeCall('users/' . $id . '/relationship', true);
200
+ }
201
+
202
+ /**
203
+ * Modify the relationship between the current user and the target user
204
+ *
205
+ * @param string $action Action command (follow/unfollow/block/unblock/approve/deny)
206
+ * @param integer $user Target user ID
207
+ * @return mixed
208
+ */
209
+ public function modifyRelationship($action, $user) {
210
+ if (true === in_array($action, $this->_actions) && isset($user)) {
211
+ return $this->_makeCall('users/' . $user . '/relationship', true, array('action' => $action), 'POST');
212
+ }
213
+ throw new Exception("Error: modifyRelationship() | This method requires an action command and the target user id.");
214
+ }
215
+
216
+ /**
217
+ * Search media by its location
218
+ *
219
+ * @param float $lat Latitude of the center search coordinate
220
+ * @param float $lng Longitude of the center search coordinate
221
+ * @param integer [optional] $distance Distance in metres (default is 1km (distance=1000), max. is 5km)
222
+ * @param long [optional] $minTimestamp Media taken later than this timestamp (default: 5 days ago)
223
+ * @param long [optional] $maxTimestamp Media taken earlier than this timestamp (default: now)
224
+ * @return mixed
225
+ */
226
+ public function searchMedia($lat, $lng, $distance = 1000, $minTimestamp = NULL, $maxTimestamp = NULL) {
227
+ return $this->_makeCall('media/search', false, array('lat' => $lat, 'lng' => $lng, 'distance' => $distance, 'min_timestamp' => $minTimestamp, 'max_timestamp' => $maxTimestamp));
228
+ }
229
+
230
+ /**
231
+ * Get media by its id
232
+ *
233
+ * @param integer $id Instagram media ID
234
+ * @return mixed
235
+ */
236
+ public function getMedia($id) {
237
+ return $this->_makeCall('media/' . $id);
238
+ }
239
+
240
+ /**
241
+ * Get the most popular media
242
+ *
243
+ * @return mixed
244
+ */
245
+ public function getPopularMedia() {
246
+ return $this->_makeCall('media/popular');
247
+ }
248
+
249
+ /**
250
+ * Search for tags by name
251
+ *
252
+ * @param string $name Valid tag name
253
+ * @return mixed
254
+ */
255
+ public function searchTags($name) {
256
+ return $this->_makeCall('tags/search', false, array('q' => $name));
257
+ }
258
+
259
+ /**
260
+ * Get info about a tag
261
+ *
262
+ * @param string $name Valid tag name
263
+ * @return mixed
264
+ */
265
+ public function getTag($name) {
266
+ return $this->_makeCall('tags/' . $name);
267
+ }
268
+
269
+ /**
270
+ * Get a recently tagged media
271
+ *
272
+ * @param string $name Valid tag name
273
+ * @param integer [optional] $limit Limit of returned results
274
+ * @return mixed
275
+ */
276
+ public function getTagMedia($name, $limit = 0) {
277
+ return $this->_makeCall('tags/' . $name . '/media/recent', false, array('count' => $limit));
278
+ }
279
+
280
+ /**
281
+ * Get a list of users who have liked this media
282
+ *
283
+ * @param integer $id Instagram media ID
284
+ * @return mixed
285
+ */
286
+ public function getMediaLikes($id) {
287
+ return $this->_makeCall('media/' . $id . '/likes', true);
288
+ }
289
+
290
+ /**
291
+ * Get a list of comments for this media
292
+ *
293
+ * @param integer $id Instagram media ID
294
+ * @return mixed
295
+ */
296
+ public function getMediaComments($id) {
297
+ return $this->_makeCall('media/' . $id . '/comments', false);
298
+ }
299
+
300
+ /**
301
+ * Add a comment on a media
302
+ *
303
+ * @param integer $id Instagram media ID
304
+ * @param string $text Comment content
305
+ * @return mixed
306
+ */
307
+ public function addMediaComment($id, $text) {
308
+ return $this->_makeCall('media/' . $id . '/comments', true, array('text' => $text), 'POST');
309
+ }
310
+
311
+ /**
312
+ * Remove user comment on a media
313
+ *
314
+ * @param integer $id Instagram media ID
315
+ * @param string $commentID User comment ID
316
+ * @return mixed
317
+ */
318
+ public function deleteMediaComment($id, $commentID) {
319
+ return $this->_makeCall('media/' . $id . '/comments/' . $commentID, true, null, 'DELETE');
320
+ }
321
+
322
+ /**
323
+ * Set user like on a media
324
+ *
325
+ * @param integer $id Instagram media ID
326
+ * @return mixed
327
+ */
328
+ public function likeMedia($id) {
329
+ return $this->_makeCall('media/' . $id . '/likes', true, null, 'POST');
330
+ }
331
+
332
+ /**
333
+ * Remove user like on a media
334
+ *
335
+ * @param integer $id Instagram media ID
336
+ * @return mixed
337
+ */
338
+ public function deleteLikedMedia($id) {
339
+ return $this->_makeCall('media/' . $id . '/likes', true, null, 'DELETE');
340
+ }
341
+
342
+ /**
343
+ * Get information about a location
344
+ *
345
+ * @param integer $id Instagram location ID
346
+ * @return mixed
347
+ */
348
+ public function getLocation($id) {
349
+ return $this->_makeCall('locations/' . $id, false);
350
+ }
351
+
352
+ /**
353
+ * Get recent media from a given location
354
+ *
355
+ * @param integer $id Instagram location ID
356
+ * @return mixed
357
+ */
358
+ public function getLocationMedia($id) {
359
+ return $this->_makeCall('locations/' . $id . '/media/recent', false);
360
+ }
361
+
362
+ /**
363
+ * Get recent media from a given location
364
+ *
365
+ * @param float $lat Latitude of the center search coordinate
366
+ * @param float $lng Longitude of the center search coordinate
367
+ * @param integer [optional] $distance Distance in meter (max. distance: 5km = 5000)
368
+ * @return mixed
369
+ */
370
+ public function searchLocation($lat, $lng, $distance = 1000) {
371
+ return $this->_makeCall('locations/search', false, array('lat' => $lat, 'lng' => $lng, 'distance' => $distance));
372
+ }
373
+
374
+ /**
375
+ * Pagination feature
376
+ *
377
+ * @param object $obj Instagram object returned by a method
378
+ * @param integer $limit Limit of returned results
379
+ * @return mixed
380
+ */
381
+ public function pagination($obj, $limit = 0) {
382
+ if (true === is_object($obj) && !is_null($obj->pagination)) {
383
+ if (!isset($obj->pagination->next_url)) {
384
+ return;
385
+ }
386
+ $apiCall = explode('?', $obj->pagination->next_url);
387
+ if (count($apiCall) < 2) {
388
+ return;
389
+ }
390
+ $function = str_replace(self::API_URL, '', $apiCall[0]);
391
+ $auth = (strpos($apiCall[1], 'access_token') !== false);
392
+ if (isset($obj->pagination->next_max_id)) {
393
+ return $this->_makeCall($function, $auth, array('max_id' => $obj->pagination->next_max_id, 'count' => $limit));
394
+ } else {
395
+ return $this->_makeCall($function, $auth, array('cursor' => $obj->pagination->next_cursor, 'count' => $limit));
396
+ }
397
+ } else {
398
+ throw new Exception("Error: pagination() | This method doesn't support pagination.");
399
+ }
400
+ }
401
+
402
+ /**
403
+ * Get the OAuth data of a user by the returned callback code
404
+ *
405
+ * @param string $code OAuth2 code variable (after a successful login)
406
+ * @param boolean [optional] $token If it's true, only the access token will be returned
407
+ * @return mixed
408
+ */
409
+ public function getOAuthToken($code, $token = false) {
410
+ $apiData = array(
411
+ 'grant_type' => 'authorization_code',
412
+ 'client_id' => $this->getApiKey(),
413
+ 'client_secret' => $this->getApiSecret(),
414
+ 'redirect_uri' => $this->getApiCallback(),
415
+ 'code' => $code
416
+ );
417
+
418
+ $result = $this->_makeOAuthCall($apiData);
419
+ return (false === $token) ? $result : $result->access_token;
420
+ }
421
+
422
+ /**
423
+ * The call operator
424
+ *
425
+ * @param string $function API resource path
426
+ * @param array [optional] $params Additional request parameters
427
+ * @param boolean [optional] $auth Whether the function requires an access token
428
+ * @param string [optional] $method Request type GET|POST
429
+ * @return mixed
430
+ */
431
+ protected function _makeCall($function, $auth = false, $params = null, $method = 'GET') {
432
+ if (false === $auth) {
433
+ // if the call doesn't requires authentication
434
+ $authMethod = '?client_id=' . $this->getApiKey();
435
+ } else {
436
+ // if the call needs an authenticated user
437
+ if (true === isset($this->_accesstoken)) {
438
+ $authMethod = '?access_token=' . $this->getAccessToken();
439
+ } else {
440
+ throw new Exception("Error: _makeCall() | $function - This method requires an authenticated users access token.");
441
+ }
442
+ }
443
+
444
+ if (isset($params) && is_array($params)) {
445
+ $paramString = '&' . http_build_query($params);
446
+ } else {
447
+ $paramString = null;
448
+ }
449
+
450
+ $apiCall = self::API_URL . $function . $authMethod . (('GET' === $method) ? $paramString : null);
451
+
452
+ $ch = curl_init();
453
+ curl_setopt($ch, CURLOPT_URL, $apiCall);
454
+ curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json'));
455
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
456
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
457
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
458
+
459
+ if ('POST' === $method) {
460
+ curl_setopt($ch, CURLOPT_POST, count($params));
461
+ curl_setopt($ch, CURLOPT_POSTFIELDS, ltrim($paramString, '&'));
462
+ } else if ('DELETE' === $method) {
463
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
464
+ }
465
+
466
+ $jsonData = curl_exec($ch);
467
+ if (false === $jsonData) {
468
+ throw new Exception("Error: _makeCall() - cURL error: " . curl_error($ch));
469
+ }
470
+ curl_close($ch);
471
+
472
+ return json_decode($jsonData);
473
+ }
474
+
475
+ /**
476
+ * The OAuth call operator
477
+ *
478
+ * @param array $apiData The post API data
479
+ * @return mixed
480
+ */
481
+ private function _makeOAuthCall($apiData) {
482
+ $apiHost = self::API_OAUTH_TOKEN_URL;
483
+
484
+ $ch = curl_init();
485
+ curl_setopt($ch, CURLOPT_URL, $apiHost);
486
+ curl_setopt($ch, CURLOPT_POST, count($apiData));
487
+ curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($apiData));
488
+ curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json'));
489
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
490
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
491
+
492
+ $jsonData = curl_exec($ch);
493
+ if (false === $jsonData) {
494
+ throw new Exception("Error: _makeOAuthCall() - cURL error: " . curl_error($ch));
495
+ }
496
+ curl_close($ch);
497
+
498
+ return json_decode($jsonData);
499
+ }
500
+
501
+ /**
502
+ * Access Token Setter
503
+ *
504
+ * @param object|string $data
505
+ * @return void
506
+ */
507
+ public function setAccessToken($data) {
508
+ (true === is_object($data)) ? $token = $data->access_token : $token = $data;
509
+ $this->_accesstoken = $token;
510
+ }
511
+
512
+ /**
513
+ * Access Token Getter
514
+ *
515
+ * @return string
516
+ */
517
+ public function getAccessToken() {
518
+ return $this->_accesstoken;
519
+ }
520
+
521
+ /**
522
+ * API-key Setter
523
+ *
524
+ * @param string $apiKey
525
+ * @return void
526
+ */
527
+ public function setApiKey($apiKey) {
528
+ $this->_apikey = $apiKey;
529
+ }
530
+
531
+ /**
532
+ * API Key Getter
533
+ *
534
+ * @return string
535
+ */
536
+ public function getApiKey() {
537
+ return $this->_apikey;
538
+ }
539
+
540
+ /**
541
+ * API Secret Setter
542
+ *
543
+ * @param string $apiSecret
544
+ * @return void
545
+ */
546
+ public function setApiSecret($apiSecret) {
547
+ $this->_apisecret = $apiSecret;
548
+ }
549
+
550
+ /**
551
+ * API Secret Getter
552
+ *
553
+ * @return string
554
+ */
555
+ public function getApiSecret() {
556
+ return $this->_apisecret;
557
+ }
558
+
559
+ /**
560
+ * API Callback URL Setter
561
+ *
562
+ * @param string $apiCallback
563
+ * @return void
564
+ */
565
+ public function setApiCallback($apiCallback) {
566
+ $this->_callbackurl = $apiCallback;
567
+ }
568
+
569
+ /**
570
+ * API Callback URL Getter
571
+ *
572
+ * @return string
573
+ */
574
+ public function getApiCallback() {
575
+ return $this->_callbackurl;
576
+ }
577
+
578
+ }
app/code/community/Neklo/Instagram/etc/adminhtml.xml ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ NOTICE OF LICENSE
4
+
5
+ This source file is subject to the NekloEULA that is bundled with this package in the file ICENSE.txt.
6
+
7
+ It is also available through the world-wide-web at this URL: http://store.neklo.com/LICENSE.txt
8
+
9
+ Copyright (c) Neklo (http://store.neklo.com/)
10
+ -->
11
+ <config>
12
+ <acl>
13
+ <resources>
14
+ <admin>
15
+ <children>
16
+ <system>
17
+ <children>
18
+ <config>
19
+ <children>
20
+ <neklo_instagram translate="title" module="neklo_instagram">
21
+ <title>Neklo Instagram Widget</title>
22
+ <sort_order>9998</sort_order>
23
+ </neklo_instagram>
24
+ </children>
25
+ </config>
26
+ </children>
27
+ </system>
28
+ </children>
29
+ </admin>
30
+ </resources>
31
+ </acl>
32
+ </config>
app/code/community/Neklo/Instagram/etc/config.xml ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ NOTICE OF LICENSE
4
+
5
+ This source file is subject to the NekloEULA that is bundled with this package in the file ICENSE.txt.
6
+
7
+ It is also available through the world-wide-web at this URL: http://store.neklo.com/LICENSE.txt
8
+
9
+ Copyright (c) Neklo (http://store.neklo.com/)
10
+ -->
11
+ <config>
12
+ <modules>
13
+ <Neklo_Instagram>
14
+ <version>1.0.0</version>
15
+ </Neklo_Instagram>
16
+ </modules>
17
+ <frontend>
18
+ <layout>
19
+ <updates>
20
+ <neklo_instagram>
21
+ <file>neklo_instagram.xml</file>
22
+ </neklo_instagram>
23
+ </updates>
24
+ </layout>
25
+ </frontend>
26
+ <adminhtml>
27
+ <translate>
28
+ <modules>
29
+ <Neklo_Instagram>
30
+ <files>
31
+ <default>Neklo_Instagram.csv</default>
32
+ </files>
33
+ </Neklo_Instagram>
34
+ </modules>
35
+ </translate>
36
+ </adminhtml>
37
+ <global>
38
+ <blocks>
39
+ <neklo_instagram>
40
+ <class>Neklo_Instagram_Block</class>
41
+ </neklo_instagram>
42
+ </blocks>
43
+ <helpers>
44
+ <neklo_instagram>
45
+ <class>Neklo_Instagram_Helper</class>
46
+ </neklo_instagram>
47
+ </helpers>
48
+ <models>
49
+ <neklo_instagram>
50
+ <class>Neklo_Instagram_Model</class>
51
+ </neklo_instagram>
52
+ </models>
53
+ <resources>
54
+ <neklo_instagram_setup>
55
+ <setup>
56
+ <module>Neklo_Instagram</module>
57
+ </setup>
58
+ <connection>
59
+ <use>core_setup</use>
60
+ </connection>
61
+ </neklo_instagram_setup>
62
+ </resources>
63
+ </global>
64
+ <default>
65
+ <neklo_instagram>
66
+ <general>
67
+ <api_client_id></api_client_id>
68
+ <cache_lifetime>3600</cache_lifetime>
69
+ </general>
70
+ </neklo_instagram>
71
+ </default>
72
+ </config>
app/code/community/Neklo/Instagram/etc/system.xml ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ NOTICE OF LICENSE
4
+
5
+ This source file is subject to the NekloEULA that is bundled with this package in the file ICENSE.txt.
6
+
7
+ It is also available through the world-wide-web at this URL: http://store.neklo.com/LICENSE.txt
8
+
9
+ Copyright (c) Neklo (http://store.neklo.com/)
10
+ -->
11
+ <config>
12
+ <sections>
13
+ <neklo_instagram module="neklo_instagram">
14
+ <label>Instagram Widget</label>
15
+ <tab>neklo</tab>
16
+ <frontend_type>text</frontend_type>
17
+ <sort_order>200</sort_order>
18
+ <show_in_default>1</show_in_default>
19
+ <show_in_website>1</show_in_website>
20
+ <show_in_store>1</show_in_store>
21
+ <groups>
22
+ <general translate="label">
23
+ <label>General</label>
24
+ <frontend_type>text</frontend_type>
25
+ <sort_order>10</sort_order>
26
+ <show_in_default>1</show_in_default>
27
+ <show_in_website>1</show_in_website>
28
+ <show_in_store>1</show_in_store>
29
+ <fields>
30
+ <api_client_id translate="label comment">
31
+ <label>API Client ID</label>
32
+ <frontend_type>text</frontend_type>
33
+ <sort_order>10</sort_order>
34
+ <show_in_default>1</show_in_default>
35
+ <show_in_website>1</show_in_website>
36
+ <show_in_store>1</show_in_store>
37
+ <comment>{how-to-get-api-client-id}</comment>
38
+ </api_client_id>
39
+ <cache_lifetime translate="label comment">
40
+ <label>Cache Lifetime</label>
41
+ <frontend_type>text</frontend_type>
42
+ <sort_order>20</sort_order>
43
+ <show_in_default>1</show_in_default>
44
+ <show_in_website>1</show_in_website>
45
+ <show_in_store>1</show_in_store>
46
+ <validate>validate-zero-or-greater</validate>
47
+ <comment>In seconds</comment>
48
+ </cache_lifetime>
49
+ </fields>
50
+ </general>
51
+ </groups>
52
+ </neklo_instagram>
53
+ </sections>
54
+ </config>
app/code/community/Neklo/Instagram/etc/widget.xml ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ NOTICE OF LICENSE
4
+
5
+ This source file is subject to the NekloEULA that is bundled with this package in the file ICENSE.txt.
6
+
7
+ It is also available through the world-wide-web at this URL: http://store.neklo.com/LICENSE.txt
8
+
9
+ Copyright (c) Neklo (http://store.neklo.com/)
10
+ -->
11
+ <widgets>
12
+ <neklo_instagram type="neklo_instagram/widget_feed" module="neklo_instagram">
13
+ <name>Neklo Instagram Widget</name>
14
+ <parameters>
15
+ <mode translate="label">
16
+ <label>Mode</label>
17
+ <type>select</type>
18
+ <visible>1</visible>
19
+ <sort_order>10</sort_order>
20
+ <values>
21
+ <use_user_id translate="label">
22
+ <value>1</value>
23
+ <label>By User ID</label>
24
+ </use_user_id>
25
+ <use_hashtag translate="label">
26
+ <value>2</value>
27
+ <label>By Hashtag</label>
28
+ </use_hashtag>
29
+ <use_product_hashtag translate="label">
30
+ <value>3</value>
31
+ <label>By Product Hashtag</label>
32
+ </use_product_hashtag>
33
+ </values>
34
+ <value>1</value>
35
+ </mode>
36
+
37
+ <user_id translate="label description">
38
+ <label>User ID</label>
39
+ <required>0</required>
40
+ <visible>1</visible>
41
+ <type>text</type>
42
+ <value></value>
43
+ <sort_order>20</sort_order>
44
+ <description>{how-to-get-user-id}</description>
45
+ <depends><mode><value>1</value></mode></depends>
46
+ </user_id>
47
+
48
+ <hashtag translate="label">
49
+ <label>Hashtag</label>
50
+ <required>0</required>
51
+ <visible>1</visible>
52
+ <type>text</type>
53
+ <value></value>
54
+ <sort_order>30</sort_order>
55
+ <depends><mode><value>2</value></mode></depends>
56
+ </hashtag>
57
+
58
+ <title translate="label description">
59
+ <label>Title</label>
60
+ <required>0</required>
61
+ <visible>1</visible>
62
+ <type>text</type>
63
+ <value></value>
64
+ <sort_order>40</sort_order>
65
+ <description>Example: Instagram Feed #%s </description>
66
+ </title>
67
+
68
+ <description translate="label description">
69
+ <label>Description</label>
70
+ <required>0</required>
71
+ <visible>1</visible>
72
+ <type>textarea</type>
73
+ <value></value>
74
+ <sort_order>50</sort_order>
75
+ <description>Example: Description for feed #%s </description>
76
+ </description>
77
+
78
+ <limit_items translate="label">
79
+ <label>Limit</label>
80
+ <required>1</required>
81
+ <visible>1</visible>
82
+ <type>text</type>
83
+ <value>5</value>
84
+ <sort_order>60</sort_order>
85
+ </limit_items>
86
+
87
+ <image_width translate="label">
88
+ <label>Thumbnail Width</label>
89
+ <required>1</required>
90
+ <visible>1</visible>
91
+ <type>text</type>
92
+ <value>200</value>
93
+ <sort_order>70</sort_order>
94
+ </image_width>
95
+ <image_height translate="label">
96
+ <label>Thumbnail Height</label>
97
+ <required>1</required>
98
+ <visible>1</visible>
99
+ <type>text</type>
100
+ <value>200</value>
101
+ <sort_order>80</sort_order>
102
+ </image_height>
103
+
104
+ <template translate="label">
105
+ <label>Template</label>
106
+ <visible>1</visible>
107
+ <type>select</type>
108
+ <value>neklo_instagram/widget/feed.phtml</value>
109
+ <values>
110
+ <featured translate="label">
111
+ <value>neklo_instagram/widget/feed.phtml</value>
112
+ <label>Neklo Instagram Template</label>
113
+ </featured>
114
+ </values>
115
+ <sort_order>90</sort_order>
116
+ </template>
117
+ </parameters>
118
+ </neklo_instagram>
119
+ </widgets>
app/code/community/Neklo/Instagram/sql/neklo_instagram_setup/mysql4-install-1.0.0.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ NOTICE OF LICENSE
4
+
5
+ This source file is subject to the NekloEULA that is bundled with this package in the file ICENSE.txt.
6
+
7
+ It is also available through the world-wide-web at this URL: http://store.neklo.com/LICENSE.txt
8
+
9
+ Copyright (c) Neklo (http://store.neklo.com/)
10
+ */
11
+
12
+ $this->startSetup();
13
+
14
+ $instagramHashtagAttr = Mage::getModel('catalog/product')->getResource()->getAttribute('instagram_hashtag');
15
+
16
+ if (!$instagramHashtagAttr || !$instagramHashtagAttr->getId()) {
17
+ Mage::getResourceModel('catalog/setup', 'catalog_setup')->addAttribute(
18
+ Mage_Catalog_Model_Product::ENTITY, 'instagram_hashtag',
19
+ array(
20
+ 'group' => 'General',
21
+ 'type' => 'varchar',
22
+ 'backend' => '',
23
+ 'frontend' => '',
24
+ 'label' => 'Instagram Hashtag: #',
25
+ 'input' => 'text',
26
+ 'class' => '',
27
+ 'source' => '',
28
+ 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
29
+ 'visible' => true,
30
+ 'required' => false,
31
+ 'user_defined' => true,
32
+ 'default' => '',
33
+ 'searchable' => true,
34
+ 'filterable' => false,
35
+ 'comparable' => false,
36
+ 'visible_on_front' => false,
37
+ 'unique' => false,
38
+ 'apply_to' => '',
39
+ 'is_configurable' => false,
40
+ 'visible_on_front' => false,
41
+ )
42
+ );
43
+ }
44
+
45
+ $this->endSetup();
app/design/frontend/base/default/layout/neklo_instagram.xml ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ NOTICE OF LICENSE
4
+
5
+ This source file is subject to the NekloEULA that is bundled with this package in the file ICENSE.txt.
6
+
7
+ It is also available through the world-wide-web at this URL: http://store.neklo.com/LICENSE.txt
8
+
9
+ Copyright (c) Neklo (http://store.neklo.com/)
10
+ -->
11
+ <layout version="1.0.0">
12
+ <default>
13
+ <reference name="head">
14
+ <action method="addCss"><stylesheet>neklo/instagram/css/style.css</stylesheet></action>
15
+ </reference>
16
+ </default>
17
+ </layout>
app/etc/modules/Neklo_Core.xml ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ NOTICE OF LICENSE
4
+
5
+ This source file is subject to the NekloEULA that is bundled with this package in the file ICENSE.txt.
6
+
7
+ It is also available through the world-wide-web at this URL: http://store.neklo.com/LICENSE.txt
8
+
9
+ Copyright (c) Neklo (http://store.neklo.com/)
10
+ -->
11
+ <config>
12
+ <modules>
13
+ <Neklo_Core>
14
+ <active>true</active>
15
+ <codePool>community</codePool>
16
+ <extension_name>Neklo Core</extension_name>
17
+ </Neklo_Core>
18
+ </modules>
19
+ </config>
app/locale/en_US/Neklo_Core.csv ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ %s Support (%s),%s Support (%s)
2
+ Contact Email,Contact Email
3
+ Contact Form,Contact Form
4
+ Contact Name,Contact Name
5
+ "Contact Neklo Support Team or visit <a href=""%s"" target=""_blank"">%s</a> for additional information","Contact Neklo Support Team or visit <a href=""%s"" target=""_blank"">%s</a> for additional information"
6
+ Extensions &amp; Contact,Extensions &amp; Contact
7
+ Extensions Information,Extensions Information
8
+ Installed Neklo Extensions,Installed Neklo Extensions
9
+ free,free
10
+ Magento Related Support (paid),Magento Related Support (paid)
11
+ Message,Message
12
+ Neklo Extensions &amp; Contact,Neklo Extensions &amp; Contact
13
+ Other Reason,Other Reason
14
+ Reason,Reason
15
+ Request New Extension Development (paid),Request New Extension Development (paid)
16
+ paid,paid
17
+ Please select,Please select
18
+ Send,Send
19
+ Subject,Subject
app/locale/en_US/Neklo_Instagram.csv ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {how-to-get-api-client-id},"<a href='http://darkwhispering.com/how-to/get-a-instagram-client_id-key' target='_blank'>How to get?</a>"
2
+ {how-to-get-user-id},"<a href='http://jelled.com/instagram/lookup-user-id' target='_blank'>How to get?</a>"
3
+ API Client ID,API Client ID
4
+ By Hashtag,By Hashtag
5
+ By Product Hashtag,By Product Hashtag
6
+ By User ID,By User ID
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
+ Neklo Instagram Template,Neklo Instagram Template
15
+ Template,Template
16
+ Thumbnail Height,Thumbnail Height
17
+ Thumbnail Width,Thumbnail Width
18
+ Title,Title
19
+ User ID,User ID
app/locale/en_US/template/email/neklo_contact.html ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <!--@subject [Neklo Contact] {{var subject}} @-->
2
+ ID: {{var id}}
3
+ Reason: {{var reason}}
4
+ Magento: {{var version}}
5
+ URL: {{var url}}
6
+
7
+ {{var message}}
app/locale/en_US/template/email/neklo_contact_copy.html ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <!--@subject [Neklo Contact Copy] {{var subject}} @-->
2
+ Reason: {{var reason}}
3
+ Magento: {{var version}}
4
+ URL: {{var url}}
5
+
6
+ {{var message}}
package.xml ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>neklo_instagram</name>
4
+ <version>1.0.0</version>
5
+ <stability>stable</stability>
6
+ <license>OSL</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>Free Magento Community extension that adds Instagram to your online store.</summary>
10
+ <description>&lt;p&gt;The influence of social networks has spread over all the spheres nowadays, including sales. Giving people a sense of being a part of a global community, they create trends and make us follow them. Being one of the most popular social networking services ever, Instagram is what you need to have on a store to take integration with your customers to a new level.&lt;/p&gt;&lt;p&gt;The only thing that may prevent you from doing it is that in standard Magento there is no feature allowing to display an Instagram feed. And we found a solution. With our &lt;b&gt;Instagram Widget&lt;/b&gt; you can easily integrate this service into your store to get closer to the customers.&lt;/p&gt;&lt;p&gt;You can insert this widget into a CMS page, static blocks or create a custom widget. Use the widget options to set its title, description, thumbnail size, number of posts and the widget mode.&lt;/p&gt;&lt;p&gt;There are three of them defining the way Instagram posts will be displayed in the backend: by user ID, by hashtag or by product hashtag. If you wish you can additionally customize the widget&amp;rsquo;s appearance using SaaS to make it look even better on your store. On clicking the image your customers get redirected straight to the corresponding Instagram page.&lt;/p&gt;&lt;p&gt;Try our free NEKLO Instagram Widget and brighten up your store.&lt;/p&gt;&#xD;
11
+ &lt;h3&gt;Features&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Can be placed anywhere on a store&lt;/li&gt;&lt;li&gt;Any number of image blocks can be shown&lt;/li&gt;&lt;li&gt;3 posts display modes&lt;/li&gt;&lt;li&gt;Clear settings&lt;/li&gt;&lt;/ul&gt;</description>
12
+ <notes>First release</notes>
13
+ <authors><author><name>Neklo</name><user>Neklo</user><email>info@neklo.com</email></author></authors>
14
+ <date>2015-08-25</date>
15
+ <time>12:45:11</time>
16
+ <contents><target name="magecommunity"><dir name="Neklo"><dir name="Instagram"><dir name="Block"><dir name="Widget"><file name="Feed.php" hash="44702a26547f33ead5cc59fc994b01e2"/></dir></dir><dir name="Helper"><file name="Data.php" hash="cb10f0786d9d427696703c0b462fee27"/></dir><dir name="Model"><dir name="Instagram"><file name="Api.php" hash="2c9ffa57fd24e9d02a85e806abe5fca6"/></dir><file name="Instagram.php" hash="4cd293b3dba67dd589db6d1a60add66e"/></dir><dir name="etc"><file name="adminhtml.xml" hash="2f4b00df3c1e3d13a077d76a9a9bdd1b"/><file name="config.xml" hash="bab5fcdeaebfbc39987478ae1df60a6c"/><file name="system.xml" hash="c548670790e216319db8b7723fee9681"/><file name="widget.xml" hash="d68d41514afb4f987403fe75b9fa33cc"/></dir><dir name="sql"><dir name="neklo_instagram_setup"><file name="mysql4-install-1.0.0.php" hash="5af53a0fd75cb56337393d1ef67c6aba"/></dir></dir></dir><dir name="Core"><dir name="Block"><dir name="System"><file name="Abstract.php" hash="e16a321792a2964c5c2a11ac0187a3ba"/><file name="Contact.php" hash="b06cf2c4262b680a2f7b3dbba4e4204d"/><file name="Extensions.php" hash="885f31fbb037e454dd668ddab608a05a"/></dir></dir><dir name="Helper"><file name="Data.php" hash="c957254c7f03a02baa39d2f9a04eb3d7"/></dir><dir name="Model"><file name="Observer.php" hash="876314dd2db05339c880bb39a92df674"/></dir><dir name="controllers"><dir name="Adminhtml"><file name="ContactController.php" hash="266291ef971f4b98ca780d9bf4264529"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="a98c2514787de062ae6b54aface57b0d"/><file name="config.xml" hash="c7c1bca5c4a3f695e12d7cbcf9d632f2"/><file name="system.xml" hash="d458da3041f5532fbc933f7db4d7074d"/></dir></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="neklo_instagram.xml" hash="a53f39a062342f2468555dd6f6fe3422"/></dir></dir></dir></dir></target><target name="magelocal"><dir name="frontend"><dir name="base"><dir name="default"><dir name="template"><dir name="neklo_instagram"><dir name="widget"><file name="feed.phtml" hash=""/></dir></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Neklo_Core.xml" hash="2a866ece6d1095aa60802fb5f351bc13"/><file name="Neklo_Instagram.xm" hash=""/></dir></target><target name="magelocale"><dir name="en_US"><dir name="template"><dir name="email"><file name="neklo_contact.html" hash="77fad3fddd5053880402181e07afaeb6"/><file name="neklo_contact_copy.html" hash="53509ad9699516b907db459c78f477af"/></dir></dir><file name="Neklo_Core.csv" hash="e092c69e17374e68479d4de05ec8eb85"/><file name="Neklo_Instagram.csv" hash="e5c84f3edd68a29825438a1aae377204"/></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>
17
+ <compatible/>
18
+ <dependencies><required><php><min>1.4.0</min><max>1.9.2</max></php></required></dependencies>
19
+ </package>
skin/frontend/base/default/neklo/instagram/css/style.css ADDED
@@ -0,0 +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
+ }
skin/frontend/base/default/neklo/instagram/sass/mixin/_mixin.scss ADDED
@@ -0,0 +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
+ }
skin/frontend/base/default/neklo/instagram/sass/style.scss ADDED
@@ -0,0 +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
+ }