When to use __() and esc_html_e? - wordpress

Can anyone explain why I would use __() over esc_html_e()?

__() is primarily for simple text that doesn't contain markup that needs to be escaped. It differs from _e() in that the former returns the translated text while the latter echoes the translated text.
esc_html_e() and esc_html__() are similar, but they are used for strings that do contain markup. They each escape the provided string, and then call on their corresponding _e() or __() counterparts depending on which one you use.
Escaping HTML is necessary if you're accepting strings provided from user input. XSS attacks are probably the most common types of attacks on sites that accept user input and render it on the page. An attacker can easily provide <script> tags and execute arbitrary Javascript on your page if the input is not properly cleaned or escaped.

Just like the docs state, esc_html_e() retrieves a translated string, escapes it, and echoes the result. __() returns a translated string. The source for each of these functions makes this crystal clear:
function __( $text, $domain = 'default' ) {
return translate( $text, $domain );
}
function esc_html_e( $text, $domain = 'default' ) {
echo esc_html( translate( $text, $domain ) );
}

As for the purpose of esc_html_e(), as I understand it, is to prevent weird characters from translated strings (not the original ones you see in the code).
But _e() is just for translating, without any escape.

It is simple Devs. If you want to echoes or print the translated string,you can use esc_html_e & if you don't want to print that translated string & only want to return its value, you can use __().
You can take reference from esc_html_e & __() for more info.

Related

About using wordpress esc_html__

using the esc_html__ function was tiring to write text domain all the time: D so I created a function as below.
The problem is I can get the following word but it doesn't save to .pot file. If I make a direct definition of esc_html__ in the function, it works but when I use variables for dynamics, what is the reason?
// Working
function lsph_lang(){
return esc_html__( "Hello", 'lsph' );
}
lsph_lang();
// Not working.
function lsph_lang( $str ){
return esc_html__( $str, 'lsph' );
}
lsph_lang( "hello" );
Just giving you my 2cents about this translation stuff, either you are patient and keep writing the full form like this:
esc_html__( "Hello", 'lsph' )
Or you "hack it" by making that your "lsph_lang" internally generates a .php temp file which contains ALL the possible variant of your translations stuff. Doing that will ensure that tools that read the translations stuff will work as expected and you can stop writing the full form

Shortcode attributes without values and with special characters

Can Wordpress shortcodes have attributes without values like this?
[foo some_att]
I know it can be like this:
[foo some_att=""]
Can I have shortcode values like this (with curly braces)?
[foo path="{'quality': '720p', 'mp4': 'PATH_TO_MP4_VIDEO'}"]
You sure can! RichJenks has a short yet informative article on implementing this functionality, which boils down to defining a new function that can tell you if a flag (argument with no associated value) is present in your $atts array:
function is_flag( $flag, $atts ) {
foreach ( $atts as $key => $value )
if ( $value === $flag && is_int( $key ) ) return true;
return false;
}
After defining this function, you can reference is_flag() in your shortcode function to tell if the flag has been provided as part of the shortcode invocation:
if is_flag( 'some_att', $atts )
// flag is present
else
// flag is not present
Unfortunately, the example you've provided wouldn't work as an argument value with the Wordpress shortcode parser. According to the official Wordpress documentation on the Shortcode API:
Attribute values must never contain the following characters:
Square braces: [ ]
Quotes: " '
Since your example makes use of the single-quote character ('), it is officially unsupported by the shortcode parsing engine.
You can use this for first question.
is_int( array_search( 'some_att', $atts ?: [] ) )

strpos() on title in a metabox in wordpress fails to find '-'

I was coding a simple metabox for wordpress and have a little issue when saving data.
The meta box is in my "create article"-page has two textfields. These are saved as post-meta, when the post is saved.
While saving I check if the fields were filled - if they are empty I take the post title and extract the data I need. The idea is to take everything that is before the first "-". If there is no minus sign, the whole title should be saved in my custom field. Now, this fails to find "-" in the title (alltough there is one) and returns the whole title every time:
function get_from_title($title) {
$pos = strpos($title, '-');
if ($pos) {
return trim(substr($title, $pos));
}
else {
$pos = strpos($title, '–'); //added this since two different signs could be used
if ($pos) {
return trim(substr($title, $pos));
}
else {
return $title;
}
}
}
the function that is calling get_from_title is getting the title via get_the_title( $post_id ) and this works without problems.
Is wordpress encoding the title somehow? Why can't strpos find the minus sign? What should I look for instead?
Thanks
I replied to the thread you started on this topic in the WordPress forums. You can find your answer there.
Alternatively, here's what I said. :)
Ah yes. This is a tricky one. So, why can't strpos find a hyphen in
the title when clearly we can see one? Because there isn't one. hehe.
What WordPress is doing here is converting your hyphen ( minus sign )
into an en-dash.
This will give you diddly-squat:
$pos = strpos( $title, '-' );
You want this:
$pos = strpos( $title, '–' );
Let me know how things turned out for you. :)

Shortcode Attribute Containing Bracket Issue

The Shortcode API states that you can't have square brackets in your attribute. Thus, the following would not work:
[tag attribute="[Some value]"]
In my case, the square bracket is required. What would be the best solution of getting around this problem? I've already tried escaping the content in my shortcode function, but had no luck.
I am using WordPress 3.3.1.
Use some other special character in your shortcode and replace it square brackets in your shortcode function. - Since this is not what you want, here's an alternative.
This seems to be the only thing that I can think of that will work in your case, instead of relying on the Shortcode API, you can use "apply_filters" on the content, and then use preg_replace to write your own shortcode processing function.
If the brackets appear as part of the HTML generated try to use &#...; or as part of an URL use %... .
Otherwise, if it concerns your own shortcode, just replace some other character, e.g. {} by [], inside the code of the shortcode.
If it's not your own shortcode, you might modify the plugin / core. I'd write a wrapper code in order not to break updates.
We store json in shortcode attributes. We decided to use base64_encode to hide square brackets, but we faced some problems:
Themecheck complains about base64 functions
When you want to make some replace in database, for e.g. to replace all old site urls with new site url, the regex can't see what's inside a base64 encoded string
There is another solution, using htmlentities
function encode($str) {
$str = htmlentities($str, ENT_QUOTES, 'UTF-8');
// http://www.degraeve.com/reference/specialcharacters.php
$special = array(
'[' => '[',
']' => ']',
);
$str = str_replace(array_keys($special), array_values($special), $str);
return $str;
}
function decode($str) {
return html_entity_decode($str, ENT_QUOTES, 'UTF-8');
}
$original = '[1,2,3,"&",{a:1,b:2,"c":"Результат"}]';
$encoded = encode($original);
$decoded = decode($encoded);
echo "Original:\t", $original, PHP_EOL;
echo "Shortcode:\t", '[hi abc="'. $encoded .'"]', PHP_EOL;
echo "Decoded:\t", $decoded, PHP_EOL;
echo "Equal:\t\t", ($original === $decoded) ? 'YES' : 'NO';
Output
Original: [1,2,3,"&",{a:1,b:2,"c":"Результат"}]
Shortcode: [hi abc="[1,2,3,"&",{a:1,b:2,"c":"Результат"}]"]
Decoded: [1,2,3,"&",{a:1,b:2,"c":"Результат"}]
Equal: YES
http://ideone.com/fNiOkD

Removing [nid:n] in nodereference autocomplete

Using the autocomplete field for a cck nodereference always displays the node id as a cryptic bracketed extension:
Page Title [nid:23]
I understand that this ensures that selections are unique in case nodes have the same title, but obviously this is a nasty thing to expose to the user.
Has anyone had any success in removing these brackets, or adding a different unique identifier?
Ultimately, you need to change the output of nodereference_autocomplete() in nodereference.module.
To do this properly, you want a custom module to cleanly override the function.
This function is defined as a menu callback, thus,
/**
* Implementation of hook_menu_alter().
*/
function custom_module_menu_alter(&$items) {
$items['nodereference/autocomplete']['page callback'] = 'custom_module_new_nodereference_autocomplete';
}
Then, copy the nodereference_autocomplete function into your custom module, changing it's name to match your callback. Then change this one line:
$matches[$row['title'] ." [nid:$id]"] = '<div class="reference-autocomplete">'. $row['rendered'] . '</div>';
Dropping the nid reference.
$matches[$row['title']] = '<div class="reference-autocomplete">'. $row['rendered'] . '</div>';
I believe the identifier is purely cosmetic at this point, which means you could also change the text however you like. If it is not purely cosmetic, well, I haven't tested to see what will happen in the wrong conditions.
I always meant to identify how to do this. Thank you for motivating me with your question.
What Grayside has posted will work... as long as you don't have two nodes with the same title. In other words, if you want to do as Grayside has proposed, you need to be aware that the nid is not entirely unimportant. The nodereference_autocomplete_validate() function does two things. It checks to see if there is a node that matches, and if so, it passes the nid on, setting it to the $form_state array. If it can't find a node, it will set an error. If the nid is present, it will be used to get the node, which also is faster, the code is here:
preg_match('/^(?:\s*|(.*) )?\[\s*nid\s*:\s*(\d+)\s*\]$/', $value, $matches);
if (!empty($matches)) {
// Explicit [nid:n].
list(, $title, $nid) = $matches;
if (!empty($title) && ($n = node_load($nid)) && $title != $n->title) {
form_error($element[$field_key], t('%name: title mismatch. Please check your selection.', array('%name' => t($field['widget']['label']))));
}
}
This just checks to see if there is a nid and checks if that node matches with the title, if so the nid is passed on.
The 2nd option is a bit slower, but it is here errors can happen. If you follow the execution, you will see, that if will try to find a node based on title alone, and will take the first node that matches. The result of this, is that if you have two nodes with the same title, one of them will always be used. This might not be a problem for you, but the thing is, that you will never find out if this happens. Everything will work just fine and the user will think that he selected the node he wanted to. This might be the case, but he might as well have chosen the wrong node.
So in short, you can get rid of the nid in the autocomplete callback, but it has 2 drawbacks:
performance (little)
uncertainty in selecting the correct node.
So you have to think about it, before going this route. Especially, since you most likely wont be able to find the problem of the selection of the wrong nodes, should it happen. Another thing to be aware of, is that the nid showing up, also brings some valuable info to the users, a quick way to lookup the node, should they be in doubt if it is the one they want, if several nodes have similar titles.
I got Grayside's answer to work, but I had to use MENU alter, instead of the FORM alter he posted. No biggy!
function custommodule_menu_alter(&$items) {
$items['nodereference/autocomplete']['page callback'] = 'fp_tweaks_nodereference_autocomplete';
}
I've found an alternative solution is to change your widget type to select list and then use the chosen module to convert your list to an autocomplete field.
This handles nodes with the same title, and actually I think the UI is better than the one provided by the autocomplete widget.
To anyone coming across this (rather old) topic by way of a google search - for Drupal 7 please consider using entityreference module and "Entity Reference" field type if possible.
You can acheive a lot more in configuration with an "Entity Reference" field. It doesn't have this problem with the nid in square brackets.
Here is the full Drupal 7 version (References 7.x-2.1) of Grayside's answer. This goes in your custom module:
/**
* Implementation of hook_menu_alter().
*/
function custom_menu_alter(&$items) {
$items['node_reference/autocomplete/%/%/%']['page callback'] = 'custom_new_node_reference_autocomplete';
}
/**
* Implementation of Menu callback for the autocomplete results.
*/
function custom_new_node_reference_autocomplete($entity_type, $bundle, $field_name, $string = '') {
$field = field_info_field($field_name);
$instance = field_info_instance($entity_type, $field_name, $bundle);
$options = array(
'string' => $string,
'match' => $instance['widget']['settings']['autocomplete_match'],
'limit' => 10,
);
$references = node_reference_potential_references($field, $options);
$matches = array();
foreach ($references as $id => $row) {
// Markup is fine in autocompletion results (might happen when rendered
// through Views) but we want to remove hyperlinks.
$suggestion = preg_replace('/<a href="([^<]*)">([^<]*)<\/a>/', '$2', $row['rendered']);
// Add a class wrapper for a few required CSS overrides.
$matches[$row['title']] = '<div class="reference-autocomplete">' . $suggestion . '</div>'; // this is the line that was modified to remove the "[nid:XX]" disambiguator
}
drupal_json_output($matches);
}

Resources