How to "intercept" site images from Magento static cms blocks - magento

I have an extension that overrides getSkinUrl() and intercepts images coming through it, makes changes, then continues. This works for any images referenced in PHTML files.
However, This isn't catching images in CMS blocks. In the CMS blocks, I'm using
{{skin url="images/your_amazing_image.gif"}}

Magento's template variables are defined in the following file.
app/code/core/Mage/Core/Email/Template/Filter.php
For the {{skin}} variable, the following code is used around line 264 in filter.php
public function skinDirective($construction)
{
$params = $this->_getIncludeParameters($construction[2]);
$params['_absolute'] = $this->_useAbsoluteLinks;
$url = Mage::getDesign()->getSkinUrl($params['url'], $params);
return $url;
}
I'm not sure how you are overriding getSkinUrl, but make sure that the getSkinUrl method is the same method you are overriding.

Related

php codeigniter uploading photos

So I was watching a video on how to upload photos using codeigniter. The link I used is here and the code is also at this site http://code.tutsplus.com/tutorials/codeigniter-from-scratch-file-uploading-and-image-manipulation--net-9452. I got everything to work however, when I tried to use the code on my own website I ran into a problem.
Basically all I changed was that I created a template for the view to be loaded in instead of just loading a single view. There is a controller Gallery.php file that looks like the follows.
<?php
class Gallery extends CI_Controller {
function index() {
$this->load->model('Gallery_model');
if ($this->input->post('upload')) {
$this->Gallery_model->do_upload();
}
$data['images'] = $this->Gallery_model->get_images();
$this->load->view('gallery_view',$data);
}
}
I simply changed this code to. Really only changing the last line and replacing it with those new three bottom lines.
<?php
class Gallery extends CI_Controller {
function index() {
$this->load->model('Gallery_model');
if ($this->input->post('upload')) {
$this->Gallery_model->do_upload();
}
$data['images'] = $this->Gallery_model->get_images();
$var = $this->load->view('gallery_view',$data,true);
$data['center_content'] = $var;
$this->load->view('includes_main/template',$data);
}
}
Now I get an strange error that I do not understand and no error shows up in the console log. Here is a picture of the error. http://i.imgur.com/tsKNj9W.png. The error says "unable to load the requested file" then doesn't have any file name after it. then there is a .php at the bottom of the page. I just don't have a clue what is giving me this error. I checked my template over again and again, but don't see anything wrong.
My template is as follows. I commented out everything just to make sure nothing else was giving me this error. So I am just left with one line.
<?php $this->load->view($center_content); ?>
Thanks for reading. Sorry I just have been stuck on this for a while and still haven't been able to fix it.
In this case there there are many mistakes. you did not load upload library and you also did not set config array. you can find on codeigniter user guide how to upload a file. I recommend to you read this link to upload a file in codeigniter
https://ellislab.com/codeigniter/user-guide/libraries/file_uploading.html

creating a basic "hello world" to appear in Magento page header

I'm just ramping up with Magento and somethings that appear rather intuitive on the surface, don't seem to be working as expected. Here is a very basic template example that I am trying to get working at a "hello world" level before digging deeper.
In the "header" block definition in my page.xml layout I have the following block included:
<block type="core/text_list" name="helloRob" as="helloRob" template="page/html/hellorob.phtml" />
Then, in my header.phtml file, I have added...
<?php echo $this->getChildHtml('helloRob'); ?>
The contents of the hellorob.phtml file are:
<h1>Hello Rob</h1>
Yet, when displaying the page, I don't get the expected H1 element output in the header. If I remove the "getChildHtml" call and replace it with the actual HTML, then it displays the H1. So I know that my custom header.phtml file is getting loaded. I've also been able to confirm that I am adding my block to the correct layout XML file, because when I comment out another block in the same file, the commented out block no longer appears on my page.
I've checked over the code looking for something obvious, like a typo. I've also checked for any naming conflicts -- hence "helloRob" rather than "helloWorld".
I feel like I am missing something incredibly obvious, like looking for your glasses only to find them on top of your head.
Any help -- with the code -- not my glasses -- would be appreciated!
--Rob
The problem here is your understanding of block types. Blocks in Magento do different things, the one you've used here core/text_list serves a specific purpose. You can view what a block does by looking at it's code Block file, core/text_list is located in app/code/core/Mage/Core/Block/Text/List.php
protected function _toHtml()
{
$this->setText('');
foreach ($this->getSortedChildren() as $name) {
$block = $this->getLayout()->getBlock($name);
if (!$block) {
Mage::throwException(Mage::helper('core')->__('Invalid block: %s', $name));
}
$this->addText($block->toHtml());
}
return parent::_toHtml();
}
As you can see it's purpose is to just print out child blocks. This block type is used for text menus' and as blocks purely as containers for other blocks.
As you are looking for a block to just print the contents of a template so type="core/template" will do just fine, it's _toHtml() method is
protected function _toHtml()
{
if (!$this->getTemplate()) {
return '';
}
$html = $this->renderView();
return $html;
}

Including magento header outside of magento. Problems with $this->getChildHtml()

I have researched this topic pretty thoroughly but can't find an answer.
I am trying to include a Magneto head into a WordPress page. I created a new wordpress template and added the following code to it.
try {
require_once ABSPATH . '/app/Mage.php';
if (Mage::isInstalled()) {
$mage = Mage::app();
Mage::getSingleton('core/session', array('name' => 'frontend'));
if(Mage::getDesign()->designPackageExists('xxx')) {
Mage::getDesign()->setPackageName('xxx');
Mage::getDesign()->setTheme('xxx');
}
// init translator
$mage->getTranslator()->init('frontend');
// init head
$head = $mage->getLayout()->getBlockSingleton('page/html_head');
} }
Then a bit further down in the template I have
echo $head->toHtml();
Now what is happening is some parts of the head are being echoed and some parts are not.
When I go into head.phtml and try to figure out what is happening I notice that any line that contains
$this->getChildHtml()
does not get echoed.
I looked at this example and noticed that the author is manually adding the html and CSS. Why is this? Why don't they get added automatically? Is this a related problem
Thanks
To show a block that is generated inside the header block, you need to first create it, then set it as child of the header block.
eg. Here is how I display within Wordpress a Magento header block, including the currency drop-down block that was generated by getChildHtml() inside the original header.phtml:
Mage::getSingleton('core/session', array('name' => 'frontend'));
$session = Mage::getSingleton("customer/session");
$layout = Mage::getSingleton('core/layout');
$headerBlock = $layout->createBlock('page/html_header')->setTemplate('page/html/header.phtml');
$currencyBlock = $layout->createBlock('directory/currency')->setTemplate('currency/currency.phtml');
$headerBlock->setChild('currency_selector', $currencyBlock);
$headerBlock = $headerBlock->toHtml();
Then you can write the block where you need it on the page:
echo $headerBlock;
I know it's a little late but hopefully this helps others with this issue.
Are you familiar with how magento layouts are rendered? With $head = $mage->getLayout()->getBlockSingleton('page/html_head'); you create a new block without any children. That's why the author needs to add JS and CSS again. To load the default head block have a look at this thread Load block outside Magento. You can load it with $layout->getBlock('head')->toHtml();.

Magento, checkout/cart block not loading in ajax extension

I'm programming an ajax extension to Magento and I'm having trouble when I try to make checkout/cart work with it.
I want to reload the entire block, including the item and also the cart totals after a change in any product in the cart.
I've modified the layout as many sites said and I can't get the checkout/cart block render well.
My two solutions were:
1° Tryed to update the layout via an xml file, and I get a false in $block_cart.
I've a class
Mati_Ajax_CartController extends Mage_Checkout_CartController
{
...
public function updateShoppingCartAction()
{
...
$block_cart = $this->getLayout()->getBlock('checkout/cart');
...
}
}
and a xml file (which I'm sure i'ts being loaded beacause the js pointed there is loading)
<checkout_cart_updateshoppingcart>
<update handle="checkout_cart_index" />
</checkout_cart_updateshoppingcart>
2° Tryed to create the block
public function updateShoppingCartAction()
{
...
$block_cart = $this->getLayout()->getBlockSingleton('checkout/cart')->setTemplate("checkout/cart.phtml")->toHtml();
...
}
And here I get the block, but when the template executes $this->getChildHtml('totals');
It gets a false anwer, so the webpage has some differences with the previousone
Does anybody knows how to make this work ?
In your first attempt just append ->toHtml();
Alternatively you could have included that as a command in the xml output="toHtml"
Check how the checkout/onepage/review functions if you are looking for advice.
There they access the response object and then set the body of the response to the html variable, in your case $block_cart
The key was in the xml file
<ajax_cart_updateshoppingcart>
<update handle="checkout_cart_index" />
</ajax_cart_updateshoppingcart>

Images in Magento widgets

I am developing a site for a fashion client in Magento Community version 1.4.2 and as part of this project I need to have some customized home page promotion blocks to feature specific products or categories of products. For this I thought I would write my own widget and have made pretty good progress in this with the exception of how to deal with images. I need to include an image as part of the promotion. In my widget definition file I included the following parameter
<image>
<label>Image</label>
<description>Promotion image</description>
<visible>1</visible>
<type>image</type>
</image>
This seemed at first to work fine and when creating/editing a widget in the admin back end a file upload field is included in the widget options however on saving the form the image does not appear to be uploaded, or its details retained in the database. Does anyone else have experience of using images in widgets and what I may be doing wrong?
There are a couple reason why it doesn't save/upload the image:
The form enctype needs to be "multipart/form-data" for a file upload to work
Even if you change the form enctype to "multipart/form-data" you will notice if you monitor the requests that it gets POST'ed as "application/x-www-form-urlencoded" this is because it is done through ajax and ajax by itself can't process a file upload, you need to process them separately.
I have successfully implemented a "Insert Image" button which initialises the Media Library dialogue where you can browse your server for images and/or upload images.
Once the user clicks "Insert File" it inserts the full image url into a textbox in the widget so it's passed along like a normal field to your template.
This is how I achieved it:
In your widget.xml specify a new node:
<image translate="label">
<label>Image</label>
<visible>1</visible>
<required>1</required>
<type>label</type>
<helper_block>
<type>widgets/cms_wysiwyg_images_chooser</type>
<data>
<button translate="open">
<open>Insert Image...</open>
</button>
</data>
</helper_block>
</image>
The helper block type <type>widgets/cms_wysiwyg_images_chooser</type> is a custom class, so you can change it to anything you want as long as you create the class/files correctly.
<?php
class Stackoverflow_Widgets_Block_Cms_Wysiwyg_Images_Chooser extends Mage_Adminhtml_Block_Template
{
public function prepareElementHtml(Varien_Data_Form_Element_Abstract $element)
{
$config = $this->getConfig();
$chooseButton = $this->getLayout()->createBlock('adminhtml/widget_button')
->setType('button')
->setClass('scalable btn-chooser')
->setLabel($config['button']['open'])
->setOnclick('MediabrowserUtility.openDialog(\''.$this->getUrl('*/cms_wysiwyg_images/index', array('target_element_id' => $element->getName())).'\')')
->setDisabled($element->getReadonly());
$text = new Varien_Data_Form_Element_Text();
$text->setForm($element->getForm())
->setId($element->getName())
->setName($element->getName())
->setClass('widget-option input-text');
if ($element->getRequired()) {
$text->addClass('required-entry');
}
if ($element->getValue()) {
$text->setValue($element->getValue());
}
$element->setData('after_element_html', $text->getElementHtml().$chooseButton->toHtml());
return $element;
}
}
?>
And that is it! You should now have a new field in your widget options called "Image" with a textbox and a button in which you can insert the url to an image on your server and display it from your template.
A quick explanation of how it works:
A button is created that has an onclick function that calls the Media Library dialogue by calling MediabrowserUtility.openDialog() which along is passed the parameter target_element_id which tells media library what element to set the value in once they user clicks "Insert File" so we simply pass along the id of our textbox in the widget for it to receive the url of the image that the user selected.
Hope this helps someone as I couldn't find any resources out there that explained how to do it so I spent quite a while digging through Magento to work it all out :)
What I would like to do in the future is have it so it displays the image after you select it in the widget, and it stores the url in a hidden field, but having an onchange bind is not fired when the value is set to the element from js/mage/adminhtml/browser.js in the insert function, so without changing the core files it is a lot harder to do. I thought about playing around with when the form gets focus again after the Media Library closes or a timer (pretty dodgey but would work), but I have other things to move on to and may come back to it later!
UPDATE:
The URL's that the Media Library generates are like so:
http://www.yourwebsite.com/index.php/admin/cms_wysiwyg/directive/___directive/e3ttZWRpYSB1cmw9Ind5c2l3eWcvd2lkZ2V0cy9iYW5uZXIvaG9tZXBhZ2UvZm9yZWdyb3VuZC9maXNoLXRhbmsucG5nIn19/key/e8167e3884e40b97d8985e7b84e7cbc7875f134e5f7e5946c9c2a482d0279762/
Which are a cached image, and only work if the user is an admin. Stupid? Yes. If you insert the same image in to a CMS page when the html is generated for output it converts it to the original url on the server accessible via /media/wysiwyg/path/to/file/photo.jpg. We need the original url to show to the user, so what we can do is hook into the function that generates the widget html (when you click "Insert Widget") and look for /admin/cms_wysiwyg/directive/___directive/ and replace it with the original URL to the image as the CMS page does.
In your config.xml for your custom widgets:
<global>
<models>
<widget>
<rewrite>
<widget>Stackoverflow_Widgets_Model_Widget</widget>
</rewrite>
</widget>
</models>
</global>
Then create the model Widget code\local\Stackoverflow\Widgets\Model\Widget.php:
<?php
class Stackoverflow_Widgets_Model_Widget extends Mage_Widget_Model_Widget
{
public function getWidgetDeclaration($type, $params = array(), $asIs = true)
{
foreach($params as $k => $v){
if(strpos($v,'/admin/cms_wysiwyg/directive/___directive/') !== false){
$parts = explode('/',parse_url($v, PHP_URL_PATH));
$key = array_search('___directive', $parts);
if($key !== false){
$directive = $parts[$key+1];
$src = Mage::getModel('core/email_template_filter')->filter(Mage::helper('core')->urlDecode($directive));
if(!empty($src)){
$params[$k] = parse_url($src, PHP_URL_PATH);
}
}
}
}
return parent::getWidgetDeclaration($type, $params, $asIs);
}
}
Which overrides the getWidgetDeclaration function which is called every time a the widget output is produced for a textarea/wysiwyg and looks through all the parameters and if it finds an image that is linked to the admin cache it will find out the original image and overwrite the variable in the array and call the original function with the parameters.
If the cached image is not found the function will work as normal.
UPDATE: 13/09/2012
As Jonathan Day pointed out you have to overwrite Mage_Widget_Model_Widget_Instance also if you want it to work in a Widget Instance.
I haven't had the need to add an image to a widget through a Widget Instance until now and was confused why my function didn't work, until I investigated and realised the "popup" widget instances use Mage_Widget_Model_Widget and the widget instances that are used on a Widget options tab (no popup) are Mage_Widget_Model_Widget_Instance and do not extend Mage_Widget_Model_Widget so do not inherit the functionality.
To add the functionality to Mage_Widget_Model_Widget_Instance simply add the line <widget_instance>Petbarn_Widgets_Model_Widget_Instance</widget_instance> to your config.xml so it will look like:
<global>
<models>
<widget>
<rewrite>
<widget>Stackoverflow_Widgets_Model_Widget</widget>
<widget_instance>Stackoverflow_Widgets_Model_Widget_Instance</widget_instance>
</rewrite>
</widget>
</models>
</global>
Then create the model Instance code\local\Stackoverflow\Widgets\Model\Widget\Instance.php:
<?php
class Petbarn_Widgets_Model_Widget_Instance extends Mage_Widget_Model_Widget_Instance
{
protected function _beforeSave()
{
if (is_array($this->getData('widget_parameters'))) {
$params = $this->getData('widget_parameters');
foreach($params as $k => $v){
if(strpos($v,'/cms_wysiwyg/directive/___directive/') !== false){
$parts = explode('/',parse_url($v, PHP_URL_PATH));
$key = array_search('___directive', $parts);
if($key !== false){
$directive = $parts[$key+1];
$src = Mage::getModel('core/email_template_filter')->filter(Mage::helper('core')->urlDecode($directive));
if(!empty($src)){
$params[$k] = parse_url($src, PHP_URL_PATH);
}
}
}
}
$this->setData('widget_parameters', $params);
}
return parent::_beforeSave();
}
}
This time we are modifying the widget_parameters data at the start of the _beforeSave() function so it fixes up the url before it saves it.
You also have to ensure the /js/mage/adminhtml/browser.js javascript file is included (in my case it wasn't) to get the MediabrowserUtility functionality.
To ensure it is included, the easiest way is to include it for all of admin (didn't spend much time targeting it better).
Create a local.xml for adminhtml layouts (if you don't already have one): app\design\adminhtml\default\default\layout\local.xml
<?xml version="1.0"?>
<layout version="0.1.0">
<default>
<reference name="head">
<action method="addJs"><script>mage/adminhtml/browser.js</script></action>
</reference>
</default>
</layout>
This will make Magento include js/mage/adminhtml/browser.js on every page of admin so MediabrowserUtility will always be available.
NOTE: I'm using Magento Enterprise 1.11.2.0 so I'm not sure how it behaves on other versions.
I solved this use case by creating a custom field type for widgets:
<image>
<label>Image</label>
<description>Promotion image</description>
<visible>1</visible>
<type>widgetimagechooser/chooser</type>
</image>
I implemented a block Aijko_WidgetImageChooser_Block_Chooser that triggers the standard Magento image chooser element.
To solve the problem with the non clear url to the image file I implemented a custom controller Aijko_WidgetImageChooser_Adminhtml_Cms_Wysiwyg_Images_ChooserController that handles the return value from the Magento standard image chooser.
The value is added to a textbox in the widget. This relative url to the image then can be used to show the image in the frontend.
Feel free to try the extension available on Github or install directly using Magento Connect.
Thx krus for you answer! I've found a nicer way to solve the problem with the cached image URLs. I even had to do this, because your solution overwriting the Widget Model didn't work with Magento 1.7.0.2.
So what I have done is adding a new GET parameter use_file_url to the URL used for the Chooser Block:
$url = $this->getUrl(
'*/cms_wysiwyg_images/index',
array(
'target_element_id' => $element->getName(),
'use_file_url' => 1
)
);
This passes the GET parameter to the media browser. The next step is to pass this parameter to the onInsertAction of the Mage_Adminhtml_Cms_Wysiwyg_ImagesController. Do do this, you have to override the getOnInsertUrl() function of the Mage_Adminhtml_Block_Cms_Wysiwyg_Images_Content Block:
public function getOnInsertUrl()
{
$useFileUrl = (int)$this->getRequest()->getParam('use_file_url', 0);
return $this->getUrl('*/*/onInsert', array('use_file_url' => $useFileUrl));
}
Then you need to handle the new parameter in the Mage_Adminhtml_Cms_Wysiwyg_ImagesController controller:
public function onInsertAction()
{
$useFileUrl = (int)$this->getRequest()->getParam('use_file_url', 0) == 1 ? true : false;
$helper = Mage::helper('cms/wysiwyg_images');
$storeId = $this->getRequest()->getParam('store');
$filename = $this->getRequest()->getParam('filename');
$filename = $helper->idDecode($filename);
$asIs = $this->getRequest()->getParam('as_is');
Mage::helper('catalog')->setStoreId($storeId);
$helper->setStoreId($storeId);
if ($useFileUrl == false) {
$image = $helper->getImageHtmlDeclaration($filename, $asIs);
} else {
$image = $helper->getImageMediaUrl($filename);
}
$this->getResponse()->setBody($image);
}
The last step is to override the Mage_Cms_Helper_Wysiwyg_Images helper and add the getImageMediaUrl() function:
public function getImageMediaUrl($filename)
{
return $this->getCurrentUrl() . $filename;
}
I think this is a quite pretty approach, even though you have to ovverride 4 classes. But passing a GET parameter seems to be more future safe than parsing the cached URL.
There is no file uploads for widgets. To solve that problem you may use magento media browser and select image like for wysiwyg editor, but there is other issue, media browser do not return clear url of image.
As of Magento version 1.9.2.0 you will also need to add the following to your adminhtml layout file:
lib/flex.js
lib/FABridge.js
mage/adminhtml/flexuploader.js
Magento's Image custom attributes normally does not come to extension tab and you will have to go to Catalog>Product> Images to assign this attribute. But with some custom coding you can achieve this.

Resources