Magento translation of dynamic/php created text fails - php

I have a function which adds labels with numbers to form fields in a registration form. For each additional input field it adds a label like Address-2, Address-3 etc. I want to use a CSV translation file to change these labels from "Address-2" to "Number", "Address-3" to "District" etc. but it does not work. I have the correct path to the CSV as I have other text in the file which is translated correctly.
I am using the following code:
<?php for ($_i=2, $_n=$this->helper('customer/address')->getStreetLines(); $_i<=$_n; $_i++): ?>
<label for="<?php echo $this->getPrefix();?><?php echo $this->__('_street%s', $_i) ?>" <?php echo $this->__('Address %s', $_i) ?>
</label>
<?php endfor;?>
But Magento does not translate these labels, I assume due to the %s variable, which is part of the translation.
I tried different combinations in the CSV file like "Address 2", "Address "2"" but it did not work. Any ideas or suggestions on how to get this translated (either by CSV or changing the PHP code itself)?

Generally, you either store translations for entity data in the database and retrieving it by store scope. This is one of the uses of EAV storage.
Another approach would be to store these translations in custom themes and have the theme change per store.
In your case, the deciding factors for me would be (1) whether these forms which you are storing in the DB are really arbitrarily configurable or (2) if this is to be a distributed module - either of these would indicate EAV storage. Otherwise, go the theme translation route.
Update based on OP comment
"I need the variable translated" means that you are (conventionally) limited to storing the translation in the database against the entity, using the store scope. You do this any number of ways, but given that this is an extension to another extension, messing with DB schema seems out of the question. You could also manipulate inline translation, but this seems hackish (curious to hear otherwise).
This is a case where the core_block_abstract_to_html_after event may be used. The event accepts the block instance AND the rendered html. In your event observer you could perform the translation via string replace, but because this event is fired for all blocks you would want to configure it as a singleton AND test for the block type.
<?php
class Ns_Mn_Model_FormTranslate
{
public function translateLabelValues(Varien_Event_Observer $o)
{
if ($o->getBlock() instanceof The_Specific_Block_Class) {
$html = $o->getHtml();
$html = //your translation logic here
$o->setHtml($html); //this will be used
}
}
}
Main caveat here is that block_html cache will not incorporate this transformed output. Alternatively, rewrite the original class using config-based class rewrite and add transformation logic into the _html() method.

Related

Using FlexForm when creating new content cType in TYPO3 plugins

I'm adding new content types to my TYPO3 and I want to use FlexForms to define each content type options form.
I have followed this example: https://docs.typo3.org/typo3cms/extensions/fluid_styled_content/latest/AddingYourOwnContentElements/
And modified it to use FlexForms from this example: https://wiki.typo3.org/Extension_Development,_using_Flexforms
But I believe I don't quite understand the settings in Configuration/TCA/Overrrides/tt_contant.php:
// Adds content new content elements
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPlugin(
[
'LLL:EXT:lu_content/Resources/Private/Language/locallang.xlf:contacts.title',
'lu_content__contacts',
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath('lu_content').'Resources/Public/Icons/Contacts.svg',
],
'CType',
'lu_content'
);
$GLOBALS['TCA']['tt_content']['types']['lu_content__contacts']['showitem'] = 'CType;;;1-1-1,pi_flexform;;;1-1-1';
$GLOBALS['TCA']['tt_content']['columns']['pi_flexform']['config']['ds'][',lu_content__contacts'] = 'FILE:EXT:lu_content/Configuration/FlexForms/Contacts.xml';
The form works, but looks like this:
How do I get the form not to fall under Plugin Options?
And how do I make the title/header to be used in to list view? Currently i get [notitle] after save in the content list.
Thank you in advance.
PS: I'm currently developing on TYPO3 v7 but with support for v8.
The Text for the tab as well as the arrangement of any tabs and fields is defined for general plugins in
$GLOBALS['TCA']['tt_content']['types']['list']
If you have defined an own CType it's quite probable that you wish to define own fields, palettes and types, hide standard-fields and perhaps replace default labels.
The whole configuration for tt_content is quite complicated as it is used for all different content-elements and it can be seen in backend below System -> Configuration -> GLOBALS[TCA]:
The simplest option is to replace the label for the tab in $GLOBALS['TCA']['tt_content']['types']['list'].
Before / Default:
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,--palette--;;general,--palette--;;headers,--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.plugin,list_type;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:list_type_formlabel,pages;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:pages.ALT.list_formlabel,recursive,--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance,--palette--;;frames,--palette--;;appearanceLinks,--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language,--palette--;;language,--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,--palette--;;hidden,--palette--;;access,--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:categories,--div--;LLL:EXT:lang/Resources/Private/Language/locallang_tca.xlf:sys_category.tabs.category,categories,--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:notes,rowDescription,--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:extended
After / location to fill with own label: (look for ###YOUR_LABEL###):
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,--palette--;;general,--palette--;;headers,--div--;###YOUR_LABEL###,list_type;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:list_type_formlabel,pages;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:pages.ALT.list_formlabel,recursive,--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance,--palette--;;frames,--palette--;;appearanceLinks,--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language,--palette--;;language,--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,--palette--;;hidden,--palette--;;access,--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:categories,--div--;LLL:EXT:lang/Resources/Private/Language/locallang_tca.xlf:sys_category.tabs.category,categories,--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:notes,rowDescription,--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:extended
and a more difficult approach would be to define an own type in $GLOBALS['TCA']['tt_content']['types'].
Here you find The documentation about TCA.
For your case are especially interesting the following chapters:
Pallets
Types
Interface
But if you want to change labels or other configuration of single fields you'd had to refer to the chapter / configuration about columns.
In the area ctrl you still can define some general options like sorting-fields or the behavior when the whole element is copied, have a look in that chapter to get an impression about all options. Also the desired and default label and value-field is configured there with
$GLOBALS['TCA']['tt_content']['ctrl']['label']
its also possible to combine two or more fields for the default display:
$GLOBALS['TCA']['tt_content']['ctrl']['label'] = 'header';
$GLOBALS['TCA']['tt_content']['ctrl']['label_alt'] = 'subheader';
you might still want to add the option
$GLOBALS['TCA']['tt_content']['ctrl']['label_alt_force'] = 1;
Configuring the form for a plugin can take quite some time even to understand all the options, but in general there are very much options to individualize it related to many needs. It's even possible to define user-functions to handle and display own options in the form which are not covered by the existing options.

How to modify magento front end pages

I am trying to create a module which has both frontend and backend functionality. Like I need to ask for the city in the home page when the store loads. And all the available cities are entered/managed in backend admin panel.
Before I used to write for only backend things, frontend seems little confusing.
There is a design folder which is completely for theme development.
All the example are little different(https://www.mageplaza.com/magento-2-module-development/,http://inchoo.net/magento-2/how-to-create-a-basic-module-in-magento-2/]2), they have routes.xml, where route_id, and all are defined, but here I don't need any extra route. Need some additional tweaks in frontend pages.
I created module V_name/M_name/adminhtml/block controllers etc view ...
Guide me how to create a module, which has both front end and backend connection, cities should be entered in admin, they should show on the frontend homepage.
For now, I only managed to edit home page content CMS page by adding some HTML which shows a popup with a dropdown for cities when the page loads.
Since you already have the back-end figured out I will focus on front-end. Also, since all you need to do is populate a list that you already have created this should be easy. I did something like this before and I found it easier to just use JSON to query a list of, in your case the cities, and populate the drop down. I don't believe this is the most 'MVP/proper' way to go, but it is less work then the other ways. (At least for me it is. I always prefer the JavaScript option since it allows for easy future page customization.)
To use the JSON method you need to create a Block with a method like the one below. You will see that you will also have to create a Resource Model (I'm not going to go over creating the Resource Model or the details of Blocks since there are much better resources than me already online that will go into every single detail you need.). Once this is complete you can access the data straight from the .phtml page in an easy to use JSON array.
First you need to make sure you are now structuring your Modules properly. The new Block below should be in a structure like this...
app/code/<VENDOR>/<MODULE>/Block/Wrapper.php (or whatever you name it)
The admin Blocks should be in the structure below, which it sounds like you are already know how to do.
app/code/<VENDOR>/<MODULE>/Block/Adminhtml
Create your Block and add a method to create a JOSN array like below...
public function getCityList()
{
$city_array = array();
/** #var \<VENDOR>\<MODULE>\Model\ResourceModel\City\Collection $collection */
$collection = $this->_cityCollectionFactory->create();
$collection->addFieldToFilter('active','1')->addFieldToSelect(['city_id', 'city']);
$collection->getSelect()->order(array('city ASC', 'city_id ASC'));
$count = 0;
foreach ($collection as $model)
{
$city_array["$count"] = $model->getData();
$count++;
}
return \Zend_Json::encode($city_array);
}
FYI... The foreach loop in the code above is weird and uses $count because I needed to do some tricky things to get something to work.
Then you can create the Block in your .phtml file to access the data via javascript.
<?php
$block_obj = $block->getLayout()->createBlock('<VENDOR>\<MODULE>\Block\Wrapper');
?>
<script type="text/javascript">
window.citylistJson = <?php echo $block_obj->getCityList() ?>;
</script>

How to alter/remove this function's output without modifying the original theme files?

I'm using a theme framework and am trying very hard to resist the temptation of editing core files. I want to add the functionality of post formats, but I need to be able to remove certain elements for specific post formats.
function thesis_teaser_headline($post_count, $post_image) {
thesis_hook_before_teaser_headline($post_count); #hook
if ($post_image['show'] && $post_image['y'] == 'before-headline')
echo $post_image['output'];
echo '<h2 class="entry-title">' . get_the_title() . "</h2>\n";
if ($post_image['show'] && $post_image['y'] == 'after-headline')
echo $post_image['output'];
thesis_hook_after_teaser_headline($post_count); #hook
}
What would be the most efficient way to go about removing headline data for a post format such as 'link' (for example)? This function is being called to generate the content for the teasers from the homepage loop. I could just make an entire custom loop, but it won't tie in with the Thesis backend which makes it much less flexible.
Thanks!
I'm not familiar with Thesis, but I see it is calling hooks, so you could possibly put one of your functions on these, that in case you don't want any content from original thesis_teaser_headline() would turn on output buffering (ob_start()) on before hook, and clean it (ob_end_clean() or $content = ob_get_clean() if you want to alter its content, not completely replace) on after hook.
You can use the /* */ control to make the function in comment. So it will not be executed. Or put just the section you want to delete between them...
What about tweaking the html with jquery? Check on the post classes (the list of css classes that's on the div that wraps each post) to see if you can select what you need from there.
On top of all, I recommend to avoid using that framework, it's pure nightmare when you need to tweak it.

Longer Form Fields in Drupal

I have a really silly problem that has cost me a load of time already.
I have created a content template with a URL in there. When I look at the HTML code for it, I see a big fat "maxlength=256" in the form tag. I'd like to expand the length of this field, because my customer wishes to enter really long links (over 500 characters). Any idea how I can change it? When I do a generic search through the code I see so many occurences of 256, but the length might just as well be in the database somewhere. I have of course made the database field a longer varchar (1024 sounded poetic to me), so that's something I don't have to worry about.
I think it's silly, but the customer's always right, as we know.
I am using Drupal 6.14.
You want to use a hook_form_alter() in your templete.php or a custom module.
It will look something like this:
MODULE_form_alter(&$form, &$form_state, $form_id) {
if($form_id = 'name_of_form_you_want_to_alter') {
form['name_of_url_field']['#maxlength'] = 500;
}
}
Just replace MODULE with the name of your theme (if in template.php) or replace it with the name of the custom module your using.
To find the id of the form, inspect the element with firebug. Same goes for the id of the url field.
Let me know if you need more detail.
EDIT: As pointed out, it looks like you can't call hooks from the theme level.
The best way to go about this is to create a small custom module for you site. You can call it something like SITENAME_customizations.
All you need is a simple .info file named MODULENAME.info which will look something like this:
name = SITE customizations
description = "Customizations"
You will also need a MODULENAME.module file, which is where you will include your hook_form_alter call.
PS. Make sure that you don't close your php tag (?>) in your .module file.
Yahoooooo! I fixed it, thanks to the helpful Drupal pages:
http://drupal.org/node/300705
I figured out I could edit the form after it has been generated completely. The solution presented by Erik is good, but doesn't appear to work for CCK fields. In my case Erik's solution could have worked if it wasn't for this generation step that needs to happen first.
My new code is as follows:
function longerfield_form_alter(&$form, &$form_state, $form_id) {
$form['#after_build'][] = 'longerfield_after_build';
}
function longerfield_after_build($form, &$form_state) {
// This is for a node reference field:
$form['field_page_boeken'][0]['data']['url']['#maxlength'] = 1024;
return $form;
}
Now, I too see that it's ugly, especially because there might be other form elements here (just increment from 0), but it works for the first element! Yippeee!

displaying a Drupal view without a page template around it

I would like to display a Drupal view without the page template that normally surrounds it - I want just the plain HTML content of the view's nodes.
This view would be included in another, non-Drupal site.
I expect to have to do this with a number of views, so a solution that lets me set these up rapidly and easily would be the best - I'd prefer not to have to create a .tpl.php file every time I need to include a view somewhere.
I was looking for a way to pull node data via ajax and came up with the following solution for Drupal 6. After implementing the changes below, if you add ajax=1 in the URL (e.g. mysite.com/node/1?ajax=1), you'll get just the content and no page layout.
in the template.php file for your theme:
function phptemplate_preprocess_page(&$vars) {
if ( isset($_GET['ajax']) && $_GET['ajax'] == 1 ) {
$vars['template_file'] = 'page-ajax';
}
}
then create page-ajax.tpl.php in your theme directory with this content:
<?php print $content; ?>
Based on the answer of Ufonion Labs I was able to completely remove all the HTML output around the page content in Drupal 7 by implementing both hook_preprocess_page and hook_preprocess_html in my themes template.php, like this:
function MY_THEME_preprocess_page(&$variables) {
if (isset($_GET['response_type']) && $_GET['response_type'] == 'embed') {
$variables['theme_hook_suggestions'][] = 'page__embed';
}
}
function MY_THEME_preprocess_html(&$variables) {
if (isset($_GET['response_type']) && $_GET['response_type'] == 'embed') {
$variables['theme_hook_suggestions'][] = 'html__embed';
}
}
Then I added two templates to my theme: html--embed.tpl.php:
<?php print $page; ?>
and page--embed.tpl.php:
<?php print render($page['content']); ?>
Now when I open a node page, such as http://example.com/node/3, I see the complete page as usual, but when I add the response_type parameter, such as http://example.com/node/3?response_type=embed, I only get the <div> with the page contents so it can be embedded in another page.
I know this question has already been answered, but I wanted to add my own solution which uses elements of Philadelphia Web Design's (PWD) answer and uses hook_theme_registry_alter, as suggested by Owen. Using this solution, you can load the template directly from a custom module.
First, I added raw.tpl.php to a newly created 'templates' folder inside my module. The contents of raw.tpl.php are identical to PWD's page-ajax.tpl.php:
<?php print $content; ?>
Next, I implemented hook_preprocess_page in my module in the same fashion as PWD (except that I modified the $_GET parameter and updated the template file reference:
function MY_MODULE_NAME_preprocess_page(&$vars) {
if ( isset($_GET['raw']) && $_GET['raw'] == 1 ) {
$vars['template_file'] = 'raw';
}
}
Finally, I implemented hook_theme_registry_alter to add my module's 'templates' directory to the theme registry (based on http://drupal.org/node/1105922#comment-4265700):
function MY_MODULE_NAME_theme_registry_alter(&$theme_registry) {
$modulepath = drupal_get_path('module','MY_MODULE_NAME');
array_unshift($theme_registry['page']['theme paths'], $modulepath.'/templates');
}
Now, when I add ?raw=1 to the view's URL path, it will use the specified template inside my module.
For others who may hit this page, if you're just working with standard callbacks (not necessarily views), this is easy. In your callback function, instead of returning the code to render within the page, use the 'print' function.
For example:
function mymodule_do_ajax($node)
{
$rval = <<<RVAL
<table>
<th>
<td>Data</td>
<td>Data</td>
<td>Data</td>
</th>
<tr>
<td>Cool</td>
<td>Cool</td>
<td>Cool</td>
</tr>
</table>
RVAL;
//return $rval; Nope! Will render via the templating engine.
print $rval; //Much better. No wrapper.
}
Cheers!
Another way to do it which I find very handy is to add a menu item with a page callback function that doesn't return a string:
Example:
/**
* Implementation of hook_menu.
*/
function test_menu(){
$items['test'] = array (
/* [...] */
'page callback' => 'test_callback',
/* [...] */
);
return $items;
}
function test_callback() {
// echo or print whatever you want
// embed views if you want
// DO NOT RETURN A STRING
return TRUE;
}
-- Update
It would be much better to use exit(); instead of return TRUE; (see comment).
Hey, here's yet another way of doing it:
1) Download and install Views Bonus Pack (http://drupal.org/project/views_bonus)
2) Create a Views display "Feed" and use style "XML" (or something you think fits your needs better).
3) If you're not satisfied with the standard XML output, you can change it by adjusting the template for the view. Check the "theme" settings to get suggestions for alternative template names for this specific view (so you'll still have the default XML output left for future use).
Good luck!
//Johan Falk, NodeOne, Sweden
Based on answer of Philadelphia Web Design (thanks) and some googling (http://drupal.org/node/957250) here is what worked for me in Drupal 7 to get chosen pages displayed without the template:
function pixture_reloaded_preprocess_page(&$vars)
{
if ( isset($_GET['vlozeno']) && $_GET['vlozeno'] == 1 ) {
$vars['theme_hook_suggestions'][] = 'page__vlozeno';
}
}
instead of phptemplate, in D7 there has to be the name_of_your_theme in the name of the function. Also, I had to put two underscores __ in the php variable with the file name, but the actual template file name needs two dashes --
content of page--vlozeno.tpl.php :
<?php print render($page['content']); ?>
The output, however, still has got a lot of wrapping and theme's CSS references. Not sure how to output totally unthemed data...
Assuming you're in Drupal 6, the easiest way to do this is to put a phptemplate_views_view_unformatted_VIEWNAME call in template.php (assumes your view is unformatted - if it's something else, a list say, use the appropriate theme function). Theme the view results in this theme call then, instead of returning the results as you normally would, print them and return NULL. This will output the HTML directly.
PS - make sure to clear your cache (at /admin/settings/performance) to see this work.
there are probably a number of ways around this, however, the "easiest" may be just setting your own custom theme, and having the page.tpl.php just be empty, or some random divs
// page.tpl.php
<div id="page"><?php print $content ?></div>
this method would basically just allow node.tpl.php to show (or any of drupal's form views, etc...) and would be an easy way to avoid modifying core, or having to alter the theme registry to avoid displaying page.tpl.php in the first place.
edit: see comments
ok i played around with views a bit, it looks like it takes over and constructs it's own "node.tpl.php" (in a sense) for display within "page.tpl.php". on first glance, my gut feeling would be to hook into theme_registry_alter().
when you're looking at a views page, you have access to piles of information here, as well as the page.tpl.php paths/files. as such i would do something like:
function modulejustforalteration_theme_registry_alter(&$variables) {
if (isset($variables['views_ui_list_views']) ) {
// not sure if that's the best index to test for "views" but i imagine it'll work
// as well as others
$variables['page']['template'] = 'override_page';
}
}
this should allow you to use a "override_page.tpl.php" template in your current theme in which you can remove anything you want (as my first answer above).
a few things:
as i said, not sure if views_ui_list_views is always available to check against, but it sounds like it should be set if we're looking at a view
you can alter the theme paths of the page array if you prefer (to change the location of where drupal will look for page.tpl.php, instead of renaming it altogether)
there doesn't appear to be any identifiers for this specific view, so this method might be an "all views will be stripped" approach. if you need to strip the page.tpl.php for a specific view only, perhaps hooking into template_preprocess_page() might be a better idea.
I like the Drupal module. BUt, here's another way.
copy page.tpl.php in your theme folder to a new file called page-VIEWNAME.tpl.php, where VIEWNAME is the machine-readible name of the view.
Then edit page-VIEWNAME.tpl.php to suit.
There is also http://drupal.org/project/pagearray which is a general solution...
Also, #Scott Evernden's solution is a cross site scripting (XSS) security hole. Don't do that. Read the documentation on drupal.org about how to Handle Text in a Secure Fashion http://drupal.org/node/28984
A simple way to display content of a special content-type you wish to display without all the stuff of the page.tpl.php:
Add the following snippet to your template.php file:
function mytheme_preprocess_page(&$vars) {
if ($vars['node'] && arg(2) != 'edit') {
$vars['template_files'][] = 'page-nodetype-'. $vars['node']->type;
}
}
Add a page-nodetype-examplecontenttype.tpl.php to your theme, like your page.tpl.php but without the stuff you don't want to display and with print $content in the body.
If I understand your question, you want to have nodes which contain all the HTML for a page, from DOCTYPE to </HTML>. What I would do is create a content type for those nodes -- "fullhtml" as its machine-readable name -- and then create a node template for it called node-fullhtml.tpl.php. You can't just dump the node's contents, as they've been HTML-sanitized. node.fullhtml.tpl.php would literally be just this:
echo htmlspecialchars_decode($content);
Then you'll need a way to override the standard page.tpl.php. I think what you could do is at the top of your page.tpl.php check the $node's content type, and bail out if it's fullhtml. Or, set a global variable in node-fullhtml.tpl.php that page.tpl.php would check for.
I'm no Drupal expert, but that's how I'd do it. I'm talking off the cuff, so watch for devils in the details.
I see you have already gone and made yourself a module, so this may no longer help, but it is fairly easy to get a view to expose an rss feed, which might be an easier way of getting at the content, especially if you want to include it on a different site.
On D7 you can use menu_execute_active_handler
$build = menu_execute_active_handler('user', FALSE);
return render($build);
jeroen's answer was what did for me after playing with it. I have a Drupal 7 site.
First of all make sure you replace MY_THEME with your theme name. Yes it is obvious but most newbies miss this.
I actually already had a function MY_THEME_preprocess_page(&$variables) {. Do not recreate the function then but add this code at the end of the function before you close it with }.
if (isset($_GET['response_type']) && $_GET['response_type'] == 'embed') {
$variables['theme_hook_suggestions'][] = 'page__embed';
}
My function used $vars not $variables, so I had to update that as well. Again obvious if you think look for it.
My first answered allowed me to only display the node when I called it up in a web browser. However the ultimate goal of this is to embed the drupal node in an 3rd party site using iframe.
Since the release of Drupal Core 7.50 iframe is by default blocked to prevent Clickjacking
To get only the node to successfully embed in a 3rd party site you also need to override the x-frame default setting. Everything started working after I added the following in template.php
function MY_THEME_page_alter($page) {
if (isset($_GET['response_type']) && $_GET['response_type'] == 'embed') {
header_remove('X-Frame-Options');
}
}

Categories