How do I implement a browser detection into Magento to load the right language.
Example:
If a US User is surfing to my Magento shop, Magento should load the path: ..myshop../usa/
usa=storecode
If a japanese User is surfing to my Magento shop, Magento should load the path: ..myshop../jp/
jp=storecode
and so on
I guess I have to adapt the .htaccess with rewrite Urls, but I never did that before. How do I have to do it?
How does the code of browser detection look like and where do I have to put it? In the header.phtml?
thank you very very much in advance!
Edit:
index.php in CE 1.7.0.2 looks like this
/**
* Error reporting
*/
error_reporting(E_ALL | E_STRICT);
/**
* Compilation includes configuration file
*/
define('MAGENTO_ROOT', getcwd());
$compilerConfig = MAGENTO_ROOT . '/includes/config.php';
if (file_exists($compilerConfig)) {
include $compilerConfig;
}
$mageFilename = MAGENTO_ROOT . '/app/Mage.php';
$maintenanceFile = 'maintenance.flag';
if (!file_exists($mageFilename)) {
if (is_dir('downloader')) {
header("Location: downloader");
} else {
echo $mageFilename." was not found";
}
exit;
}
if (file_exists($maintenanceFile)) {
include_once dirname(__FILE__) . '/errors/503.php';
exit;
}
require_once $mageFilename;
#Varien_Profiler::enable();
if (isset($_SERVER['MAGE_IS_DEVELOPER_MODE'])) {
Mage::setIsDeveloperMode(true);
}
#ini_set('display_errors', 1);
umask(0);
/* Store or website code */
$mageRunCode = isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : '';
/* Run store or run website */
$mageRunType = isset($_SERVER['MAGE_RUN_TYPE']) ? $_SERVER['MAGE_RUN_TYPE'] : 'store';
Mage::run($mageRunCode, $mageRunType);
But this Link describes the follwing code which you cannot simply replace:
require_once 'app/Mage.php';
/* Determine correct language store based on browser */
function getStoreForLanguage()
{
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
foreach (explode(",", strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE'])) as $accept) {
if (preg_match("!([a-z-]+)(;q=([0-9.]+))?!", trim($accept), $found)) {
$langs[] = $found[1];
$quality[] = (isset($found[3]) ? (float) $found[3] : 1.0);
}
}
// Order the codes by quality
array_multisort($quality, SORT_NUMERIC, SORT_DESC, $langs);
// get list of stores and use the store code for the key
$stores = Mage::app()->getStores(false, true);
// iterate through languages found in the accept-language header
foreach ($langs as $lang) {
$lang = substr($lang,0,2);
if (isset($stores[$lang]) && $stores[$lang]->getIsActive()) return $stores[$lang];
}
}
return Mage::app()->getStore();
}
/* Auto redirect to language store view if request is for root */
if ($_SERVER['REQUEST_URI'] === '/') {
header('Location: '.getStoreForLanguage()->getBaseUrl());
exit;
}
#Varien_Profiler::enable();
#Mage::setIsDeveloperMode(true);
#ini_set('display_errors', 1);
umask(0);
Mage::run();
Can anybody help me to find out where to put it or where to adapt the index.php
Thank you again!
The request the browser sends has a field called "Accept-Language" header. It's formatting isn't so intuitive and if you wanted to do it correctly, is beyond the ability of the htaccess file and mod_rewrite to parse properly. Here's a typical "Accept-Language" request header:
Accept-Language: da, en-gb;q=0.8, en;q=0.7
Which means: "I prefer Danish, but will accept British English and other types of English"
So you can't simply look for the first two letters of the field. If you don't have Danish, then you've got to continue parsing to find the right language. Magento probably has some ways of dealing with this, for example: http://www.magentocommerce.com/wiki/multi-store_set_up/how_to_automatically_redirect_to_a_store_view_based_on_the_browser_language
Just paste the following code after require_once $mageFilename; in your CE 1.7.0.2 index.php:
/* Determine correct language store based on browser */
function getStoreForLanguage()
{
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
foreach (explode(",", strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE'])) as $accept) {
if (preg_match("!([a-z-]+)(;q=([0-9.]+))?!", trim($accept), $found)) {
$langs[] = $found[1];
$quality[] = (isset($found[3]) ? (float) $found[3] : 1.0);
}
}
// Order the codes by quality
array_multisort($quality, SORT_NUMERIC, SORT_DESC, $langs);
// get list of stores and use the store code for the key
$stores = Mage::app()->getStores(false, true);
// iterate through languages found in the accept-language header
foreach ($langs as $lang) {
$lang = substr($lang,0,2);
if (isset($stores[$lang]) && $stores[$lang]->getIsActive()) return $stores[$lang];
}
}
return Mage::app()->getStore();
}
/* Auto redirect to language store view if request is for root */
if ($_SERVER['REQUEST_URI'] === '/') {
header('Location: '.getStoreForLanguage()->getBaseUrl());
exit;
}
Make sure you don't delete or overwrite any code in your index.php file and you should be fine!
Related
I have a working WordPress Gutenberg Block project which uses nested blocks. I'm trying to rewrite the javascript save function in PHP to create a dynamic block.
I've modified the PHP file to include the following:
function render_html($attributes) {
var_dump($attributes);
ob_start(); ?>
<h1>Attributes</h1>
<h3>The number of columns is <?php echo esc_html($attributes['myColumns']) ?>!</h3>
<?php return ob_get_clean();
}
function cards_init() {
register_block_type_from_metadata( __DIR__, array(
'render_callback' => 'render_html'
) );
}
add_action( 'init', 'cards_init' );
This displays the top level attributes correctly (just one value):
C:\Users\Steve\Local Sites\netmonics6\app\public\wp-content\plugins\cards\cards.php:32:
array (size=1)
'myColumns' => int 3
Attributes
The number of columns is 3!
I'm just wondering how I access the attributes for the nested blocks?
I've used Innerblocks in the main edit.js as follows to enable a nested block:
<InnerBlocks
allowedBlocks={['some-name/card']}
orientation="horizontal"
template={[
['some-name/card'],
['some-name/card'],
['some-name/card'],
]}
/>
Does anyone please have any ideas?
Steve
InnerBlocks can be accessed via $block in the render_callback function. The syntax for the render callback is function($attributes, $content, $block) although commonly, only $attributes is used - unless you want to access something <InnerBlocks>, eg:
PHP
/*
* Render callback function
* #return string HTML markup
*/
function render_html($attributes, $content, $block)
{
$output = '';
// Loop through each inner block
foreach ($block->inner_blocks as $inner_block) {
// Eg. If your ['some-name/card'] block had an attribute
// called `someAttribute` (boolean), it could be accessed via:
if ($inner_block->someAttribute == true) {
// Do something different with this block
$output .= sprintf('<div class="is-some-attribute">%s</div>', $inner_block->render());
} else {
// Otherwise, render block as usual..
$output .= $inner_block->render();
}
}
/*
* Tip: Always return the content to render
* echo() should not be used in render_callback() and ob_start/ob_get_clean not needed.
* Returning valid content avoids dreaded "Invalid JSON" error in Editor.
*/
return $output;
}
When using InnerBlocks, the save() function in JavaScript is required so that the block editor saves the InnerBlock content (even if you are using a PHP render_callback), eg:
save.js
export default function save() {
const blockProps = useBlockProps.save();
return (
<div {...blockProps}>
<InnerBlocks.Content />
</div>
)
}
Depending on what you need from the InnerBlocks, block context might also be useful too..
Is there any way to customize the Nav Bar or the Header to have a custom link?
The use-case is that I have a JIRA issue collector that is driven by javascript. I would like the user to provide feedback from the page they are having issues. However, any solution I can come up with so far takes the user away from the current page.
Example of what I have that takes the user away:
I currently have a Suitelet that is in one of the menus. That Suitelet invokes javascript but even then the user is taken away.
I have a workflow on the case record that calls some Javascript Javascript in one of the UI-based action's conditions is invoked. Similar to #1 but on the case record.
I'm thinking I'm going to need to create and public a chrome extension for my company's domain just to get a pervasive bit of javascript to run for all pages...seems like a sledgehammer.
I hope someone can prove me wrong, but as far as I am aware there is no way to natively inject Javascript or anything into the NetSuite header/navbar - they don't offer customisation to the header/navbar.
I've resorted to creating a Userscript that I load through the Violent Monkey extension for Chrome or Firefox.
Example Userscript Template
// ==UserScript==
// #name NetSuite Mods (Example)
// #namespace Violentmonkey Scripts
// #match *.netsuite.com/*
// #include *.netsuite.com/*
// #grant GM_addStyle
// #version 1.0
// #author Kane Shaw - https://stackoverflow.com/users/4561907/kane-shaw
// #description 6/11/2020, 6:25:20 PM
// ==/UserScript==
// Get access to some commonly used NLAPI functions without having to use "unsafeWindow.nlapi..." in our code
// You can add more of these if you need access to more of the functions contained on the NetSuite page
nlapiSetFieldText = unsafeWindow.nlapiSetFieldText;
nlapiSetFieldValue = unsafeWindow.nlapiSetFieldValue;
nlapiGetFieldText = unsafeWindow.nlapiGetFieldText;
nlapiGetFieldValue = unsafeWindow.nlapiGetFieldValue;
nlapiSearchRecord = unsafeWindow.nlapiSearchRecord;
nlobjSearchFilter = unsafeWindow.nlobjSearchFilter;
nlapiLookupField = unsafeWindow.nlapiLookupField;
nlapiLoadRecord = unsafeWindow.nlapiLoadRecord;
nlapiSubmitRecord = unsafeWindow.nlapiSubmitRecord;
GM_pageTransformations = {};
/**
* The entrypoint for our userscript
*/
function GM_main(jQuery) {
// We want to execute these on every NetSuite page
GM_pageTransformations.header();
GM_pageTransformations.browsertitle();
// Here we build a function name from the path (page being accessed on the NetSuite domain)
var path = location.pathname;
if(path.indexOf('.')>-1) path = path.substr(0,path.indexOf('.'));
path = toCamelCase(path,'/');
// Now we check if a page "GM_pageTransformations" function exists with a matching name
if(GM_pageTransformations[path]) {
console.log('Executing GM_pageTransformations for '+path);
GM_pageTransformations[path]();
} else {
console.log('No GM_pageTransformations for '+path);
}
}
/**
* Changes the header on all pages
*/
GM_pageTransformations['header'] = function() {
// For example, lets make the header background red
GM_addStyle('#ns_header, #ns_header * { background: red !important; }');
}
/**
* Provides useful browser/tab titles for each NetSuite page
*/
GM_pageTransformations['browsertitle'] = function() {
var title = jQuery('.uir-page-title-secondline').text().trim();
var title2 = jQuery('.uir-page-title-firstline').text().trim();
var title3 = jQuery('.ns-dashboard-detail-name').text().trim();
if(title != '') {
document.title = title+(title2 ? ': '+title2 : '')+(title3 ? ': '+title3 : '');
} else if(title2 != '') {
document.title = title2+(title3 ? ': '+title3 : '');
} else if(title3 != '') {
document.title = title3;
}
}
/**
* Changes app center card pages (dashboard pages)
*/
GM_pageTransformations['appCenterCard'] = function() {
// For example, lets make add a new heading text on all Dashboard pages
jQuery('#ns-dashboard-page').prepend('<h1>My New Dashboard Title</h1>');
}
/**
* Convert a given string into camelCase, or CamelCase
* #param {String} string - The input stirng
* #param {String} delimter - The delimiter that seperates the words in the input string (default " ")
* #param {Boolean} capitalizeFirstWord - Wheater or not to capitalize the first word (default false)
*/
function toCamelCase(string, delimiter, capitalizeFirstWord) {
if(!delimiter) delimiter = ' ';
var pieces = string.split(delimiter);
string = '';
for (var i=0; i<pieces.length; i++) {
if(pieces[i].length == 0) continue;
string += pieces[i].charAt(0).toUpperCase() + pieces[i].slice(1);
}
if(!capitalizeFirstWord) string= string.charAt(0).toLowerCase()+string.slice(1);
return string;
}
// ===============
// CREDIT FOR JQUERY INCLUSION CODE: Brock Adams # https://stackoverflow.com/a/12751531/4561907
/**
* Check if we already have a local copy of jQuery, or if we need to fetch it from a 3rd-party server
*/
if (typeof GM_info !== "undefined") {
console.log("Running with local copy of jQuery!");
GM_main(jQuery);
}
else {
console.log ("fetching jQuery from some 3rd-party server.");
add_jQuery(GM_main, "1.9.0");
}
/**
* Add the jQuery into our page for our userscript to use
*/
function add_jQuery(callbackFn, jqVersion) {
var jqVersion = jqVersion || "1.9.0";
var D = document;
var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
var scriptNode = D.createElement ('script');
scriptNode.src = 'https://ajax.googleapis.com/ajax/libs/jquery/'
+ jqVersion
+ '/jquery.min.js'
;
scriptNode.addEventListener ("load", function () {
var scriptNode = D.createElement ("script");
scriptNode.textContent =
'var gm_jQuery = jQuery.noConflict (true);\n'
+ '(' + callbackFn.toString () + ')(gm_jQuery);'
;
targ.appendChild (scriptNode);
}, false);
targ.appendChild (scriptNode);
}
You can copy and paste that code as-is into a new Userscript and it will do the following:
Make Browser tabs/windows have useful titles (shows order numbers, customer names, vendor names etc - not just "Sales Order")
Change the header background to red (as an example)
Add a new heading to the top of all "Dashboard" pages that says "My New Dashboard Title" (as an example)
What i want to do is, to detect the language of a users browser and redirect him to a page containing the locale in url.
I thought, the easiest way would be, to register a kernel listener. So that is what i did:
services:
kernel__request_listener:
class: Me\MainBundle\Listener\KernelRequestListener
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
calls:
- [ setContainer, [ #service_container ] ]
KernelRequestListener.php
...
/**
* #Service
*/
class KernelRequestListener
{
/**
* #Observe("kernel.request")
*/
public function onKernelRequest( GetResponseEvent $response )
{
if( $newLocale = $this->newLocale() )
{
$parmArray = $request->get('_route_params');
$parmArray['_locale'] = $newLocale;
$redirectResponse = new RedirectResponse( $this->getContainer()->get('router')->generate($request->get('_route'), $parmArray) );
$redirectResponse->headers->setCookie( new Cookie('b_locale', $newLocale, time() + 2592000) );
$response->setResponse( $redirectResponse );
}
}
...
}
The method $this->newLocale() just detects if the user should be redirected to another language and returns the new language code (i.e. DE or FR).
Here comes the problem:
I am using assetics to compress the js files and jms/i18n-routing-bundle to do the locale-based routing. When the kernel listener switches locale, the page starts loading the js files over and over again. also, there are several pages (i.e. the profiler, login/logout etc.) where no redirect should take place as it makes no sense or breaks smthing.
Is a kernel listener the right place to do such a redirection or is there any better place. How to resolve the problems above?
Add, before your code:
public function onKernelRequest(GetResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
}
$request = $event->getRequest();
if ($request->getRequestFormat() !== 'html') {
return;
}
[CODE]
here it's my end of link : .../home#&ui-state=dialog. I would fix this link through htaccess in this way the link is /home/info. How could I do?
So you want to load a page based on the url hash (junk preceding #)?
In JQuery, something like:
$(window).bind('hashchange',function() {
var hash = window.location.hash;
if (hash == '&ui-state=dialog') {
window.location.href = '/home/info';
}
else {
...
}
});
In the last days, I'm working on the application which needs to search for users on Facebook. Since the FQL query for "username" was deprecated/canceled, I have decided to use common search API.
I use PHP so FB PHP SDK is the way I'd prefer. I have used it earlier for FQL queries, just like this:
// $api is already initialized, with access_key, app secret and so on
$users = $api(array(
'method' => 'fql.query',
'query' => "SELECT first_name,last_name FROM user WHERE uid='12345'",
));
I'd like to build the search query in the similar way. Especially, I don't want to urlencode the parameters, specify access key, app secret and all the stuff the SDK is supposed to do for me. However, I haven't been able to build this query using SDK yet. Is there any possibility to do it? If yes, how? I have found long list of sdk-supported "api calls" but I need to build the query for graph.facebook.com/search?arguments.
Thanks in advance.
EDIT: To make it clear, I don't want to build the string by myself. I know this solution works. But imho it's ugly when I have SDK:
$name = urlencode(trim($first_name . " " . $last_name_));
$users = $this->facebook->api("/search?q=$name&type=user&access_token=$key");
Searching User via Graph API using php-sdk 3.1.1
User will need to authorize your app before making a search for
users.
{
"error": {
"message": "A user access token is required to request this resource.",
"type": "OAuthException"
}
}
Php-skd 3.1.1 init.
<?php
require './src/facebook.php';
$facebook = new Facebook(array(
'appId' => 'your-app-id',
'secret' => 'your-app-secret',
));
$user = $facebook->getUser();
if ($user) {
try {
// Proceed knowing you have a logged in user who's authenticated.
$user_profile = $facebook->api('/me');
} catch (FacebookApiException $e) {
error_log($e);
$user = null;
}
}
/* */
if ($user) {
$logoutUrl = $facebook->getLogoutUrl();
} else {
$loginUrl = $facebook->getLoginUrl();
}
?>
Search includes, encoding search term, setting results limit, and
offset for paging.
<?php
/* Get Search parameter from url or post and urlencode it. */
$q = urlencode($_GET['qs']);
if(!$_GET['qs']){
$q = urlencode($_POST['qs']);
if(!$_POST['qs']){
/* Default Search Term */
$q = "Shawn+E+Carter";
}
}
/* Get Results Limit from url or set default. */
$limit = $_GET['limit'];
if (!$_GET['limit']){
$limit = 60;
}
/* Get Offset from url or set default for paging. */
$offset = $_GET['offset'];
if (!$_GET['offset']){
$offset = 0;
}
/* Make Graph API call to user */
$usersearch = 'search%3Fq='.$q.'%26type=user%26limit='.$limit.'%26offset='.$offset.'';
echo '<pre style="text-align: left;">';
print_r($usersearch);
echo '</pre>';
?>