WP Oembed not passing through the “autoplay=1” variable - php

I'm having this problem.
I am passing this through a custom field here
(notice the "autoplay=1")
But when I load the video on my theme using wp_oembed_get... it displays the video fine, but it does not listen to the autoplay=1 variable I am passing through.
I need the videos to play on the load of the page.

I think the way to do it is using wordpress filters:
function modify_youtube_embed_url($html) {
return str_replace("?feature=oembed", "?feature=oembed&autoplay=1", $html);
}
add_filter('oembed_result', 'modify_youtube_embed_url');

This is my solution in functions.php
function embed_responsive_autoplay($code){
if(strpos($code, 'youtu.be') !== false || strpos($code, 'youtube.com') !== false){
$return = preg_replace('#embed/([^"&]*)#', 'embed/$1&showinfo=0&autoplay=1', $code);
return '<div class="embed-container">' . $return . '</div>';
}
return '<div class="embed-container">' . $code . '</div>';
}
add_filter( 'embed_oembed_html', 'embed_responsive_autoplay');
add_filter( 'video_embed_html', 'embed_responsive_autoplay' ); // Jetpack
Enjoy!

look up function wp_oembed_get and use the args to pass the autoplay... should work fine. Just paste in the url of the video not the &autoplay... you'll code that into the args part of the function.

So, after some research on this, the best way to do this is to leverage the oembed_fetch_url filter hook to add extra arguments to the oEmbed request URL. My specific goal was to allow an autoplay paramater, but this method is built to be easy to tailor to any oEmbed argument you need.
First, add this to your functions.php:
<?php
/**
* Add parameters to embed
* #src https://foxland.fi/adding-parameters-to-wordpress-oembed/
* #src https://github.com/WordPress/WordPress/blob/ec417a34a7ce0d10a998b7eb6d50d7ba6291d94d/wp-includes/class-oembed.php#L553
*/
$allowed_args = ['autoplay'];
function koa_oembed_args($provider, $url, $args) {
global $allowed_args;
$filtered_args = array_filter(
$args,
function ($key) use ($allowed_args) {
return in_array($key, $allowed_args);
},
ARRAY_FILTER_USE_KEY
);
foreach ($filtered_args as $key => $value) {
$provider = add_query_arg($key, $value, $provider);
}
return $provider;
}
add_filter('oembed_fetch_url', 'koa_oembed_args', 10, 3);
This function takes the generated oEmbed URL and its corresponding arguments and checks it agains a hard-coded list of whitelisted arguments, in this case ['autoplay']. If it sees any of these whitelisted keywords in the arguments passed to the oEmbed filter, it adds them with their given value to the oEmbed URL.
Then, all you need to do is add the oEmbed parameter to your shortcode in the Wordpress editor, like this:
[embed autoplay="true"]https://vimeo.com/1234567890/1234567890[/embed]
Be aware that the oEmbed class in WP uses the postmeta as a cache for these requests, so if you've embedded the target URL before, you might have to clear your postmeta cache in some way or add a cache buster of some kind to the target URL. If the link is in the cache, the filter hook will never get to run.
I hope this makes sense, as I feel like it's a pretty useful feature that's surprisingly hard to figure out how to achieve.

This can be easily fixed by modifying the wp_oembed_get() function in wp-includes/media.php to this:
function wp_oembed_get( $url, $args = '' ) {
// Manually build the IFRAME embed with the related videos option disabled and autoplay turned on
if(preg_match("/youtube.com\/watch\?v=([^&]+)/i", $url, $aMatch)){
return '<iframe width="560" height="315" src="http://www.youtube.com/embed/' . $aMatch[1] . '?rel=0&autoplay=1" frameborder="0" allowfullscreen></iframe>';
}
require_once( ABSPATH . WPINC . '/class-oembed.php' );
$oembed = _wp_oembed_get_object();
return $oembed->get_html( $url, $args );
}

Related

The best way to use variables on all WordPress pages

I'm building a custom theme that has a lot of variables that I wish to use throughout.
Example:
$tv = $options['tv'];
$movies = $options['movies'];
$print = $options['print'];
//....and about 50 more.
For this purpose I have been simply placing them all in a file called vars.php and then in header.php of the theme I include it...
require_once('vars.php');
While this does work, it doesn't feel like the best way. I've read on numerous occasions that use global variables (presumably in functions.php) isn't a good idea, but is this true?
But if it's fine to use global variables in functions.php (even lots of them) is this the right way to go about it?:
global $tv;
$tv = $options['tv'];
global $movies
$movies = $options['movies'];
global $print
$print = $options['print'];
The best way for this is to define all the variables explicitly in functions.php or in main plugin file for plugin. I have verified this is the way most popular plugins including akismet use. Specifically you need to do this.
define( MYVAR_TV, $options['tv'] );
define( MYVAR_MOVIES, $options['movies'] );
define( MYVAR_PRINT, $options['print'] );
After these you can just use them whereever you want like
echo MYVAR_TV;
Hope it helps.
It's fine to use global, but it's not encouraged (you can read more here Are global variables in PHP considered bad practice? If so, why?). You may consider Singleton implementation:
<?php
class GlobalVariable {
/**
* #var array
*/
public static $option = [];
}
// You can set the variable using this way
GlobalVariable::$option['movies'] = 1;
// And get the variables using that array
print_r(GlobalVariable::$option);
Hope this can help you.
What about creating a function in functions.php that returns an array of your variables?
Example: $options = get_my_custom_vars();
I'm assuming that you would like global variables, where it makes an array with all your variables. To use it:
$GLOBALS['your-varriable']
Source:
PHP Documentation
I personally like using Acf Options Addon. Altering these and having them translatable via the wpml plugin is useful, too.
These Options will be addable/editable within a "Options Page" in the Backend or as programmed as described in the link.
After initializing the addon via the functions.php
if( function_exists('acf_add_options_page') ) {
acf_add_options_page();
}
simply call these in the template via
<?php the_field('header_title', 'option'); ?>
These examples were taken from the Acf Options Page documentation.
Keep in mind https://www.advancedcustomfields.com/ has to be installed for this to work.
You can implement a custom stream wrapper, too. This way you could access and store data using functions like file_get_contents, file_put_contents, fread, fwrite, etc. Just like reading and writing from a file, or getting info from a remote URL.
Actually there is an example in the PHP manual, using global variables like you ask. But lets pull it from there in order of completeness and adapting it to your use case in WP and examples of use.
<?php
// variable-stream-class.php just this is pulled from the PHP manual
class VariableStream {
var $position;
var $varname;
function stream_open($path, $mode, $options, &$opened_path)
{
$url = parse_url($path);
$this->varname = $url["host"];
$this->position = 0;
return true;
}
function stream_read($count)
{
$ret = substr($GLOBALS[$this->varname], $this->position, $count);
$this->position += strlen($ret);
return $ret;
}
function stream_write($data)
{
$left = substr($GLOBALS[$this->varname], 0, $this->position);
$right = substr($GLOBALS[$this->varname], $this->position + strlen($data));
$GLOBALS[$this->varname] = $left . $data . $right;
$this->position += strlen($data);
return strlen($data);
}
function stream_tell()
{
return $this->position;
}
function stream_eof()
{
return $this->position >= strlen($GLOBALS[$this->varname]);
}
function stream_seek($offset, $whence)
{
switch ($whence) {
case SEEK_SET:
if ($offset < strlen($GLOBALS[$this->varname]) && $offset >= 0) {
$this->position = $offset;
return true;
} else {
return false;
}
break;
case SEEK_CUR:
if ($offset >= 0) {
$this->position += $offset;
return true;
} else {
return false;
}
break;
case SEEK_END:
if (strlen($GLOBALS[$this->varname]) + $offset >= 0) {
$this->position = strlen($GLOBALS[$this->varname]) + $offset;
return true;
} else {
return false;
}
break;
default:
return false;
}
}
function stream_metadata($path, $option, $var)
{
if($option == STREAM_META_TOUCH) {
$url = parse_url($path);
$varname = $url["host"];
if(!isset($GLOBALS[$varname])) {
$GLOBALS[$varname] = '';
}
return true;
}
return false;
}
}
Let's suppose you have a plugin to isolate your functions, being able to deactivate it for debugging and not losing it if you change the active theme. I'd recommend putting something like this in your plugin entrypoint:
<?php
/**
* Plugin Name: Stream Wrapper for global variables
* Plugin URI: https://stackoverflow.com/q/46248656/
* Description: Utility class and functions to enable global data sharing in WordPress
* Author: Jesús E. Franco Martínez and the PHP Documentation Group
* Contributors: tzkmx
* Version: 0.1
* Author URI: https://tzkmx.wordpress.com
*/
require 'variable-stream-class.php';
stream_wrapper_register("var", "VariableStream")
or wp_die("Failed to register protocol", null, ['back_link' => true]);
Then, in your templates or other site plugins you can use the above mentioned functions, or use custom aliases. Let's expand on your request:
// functions.php in your theme or better, in the same plugin.php above
// Using a hook just for frontend in order to get populated
// our variables without require calls in the theme.
add_action('wp_head', 'populate_my_awesome_plugin_options');
function populate_my_awesome_plugin_options() {
// Let's say you get your data from a single get_option call
$options = get_option( 'my_awesome_plugin_options' );
foreach( $options as $key => $value ) {
file_put_contents( 'var://' . $key, $value );
}
}
function pop_get_var( $var_name ) {
return file_get_contents( 'var://' . $var_name );
}
Finally, in the header.php or whatever template file you are going to consume your data, the call is just like this:
<p>TV favorite show: <strong><?= pop_get_var( 'tv' ) ?></strong></p>
<p>Movies I like: <strong><?= pop_get_var( 'movies' ) ?></strong></p>
<p>Impressum: <em><?= pop_get_var( 'print' ) ?></em></p>
I know it may look like a lot of boilerplate at first, but because of separation of concerns, you are not limited only to scalar values like using constants, also your stream wrapper could be an adapter to whatever data store you like and not only in memory or stored in WordPress options table. And using a custom function eases you the hassle of writing such long calls to a singleton class, or calling global wherever you want to access your custom data.
Actually if you read the examples in the PHP manual, you'll find an example of using the wrapper to store an entire text, that you could call with include. There is nothing stopping you from using even serialized data, in example with json_encode/json_decode, and stored with your wrapper, even directly in the database with little effort. There is another example to write/read data from a database with PDO, but is easily ported to use WordPress $wpdb object.

Wordpress add_rewrite_tag(), add_rewrite_rule(), and post_link()

I am trying to do the following:
Rewrite the URL structure of my WordPress installation so that a language field is in there. E.g. http://www.mydomain.com/lang/
I want to then take the input from /lang/ and use it to display the appropriate content. E.g. if lang is 'en' I will take custom fields in English and display the theme in English.
Here is what I have so far:
<?php
function add_directory_rewrite() {
global $wp_rewrite;
add_rewrite_tag('%lang%', '(.+)');
add_rewrite_rule('^/(.+)/', 'index.php?p=$matches[1]&lang=$matches[2]', 'top');
add_permastruct('lang', '%lang%');
}
add_action( 'init', 'add_directory_rewrite' );
?>
This works as far as getting the language but the problem I am facing is now the_permalink() has "/%lang%/" where /en/ is supposed to be or /fr/ or /de/ or whatever language. To add more detail my permalink structure is /%lang%/%category%/%postname%/ and lets say I have a category called food and a post with the title chicken, the_permalink will generate http://www.mydomain.com/%lang%/food/chicken/
Any idea what I'm doing wrong? Cheers.
You additionally need to add a function that will take the permalink that contains the erroneous '/%lang%/' segment, and replace it with the appropriate default language for the post. Typically you can do this either by the 'pre_post_link' filter, or the 'post_link' filter. If you use the former, you will be creating the permalink from scratch (totally custom urls that use nothing that core WP has to offer). If the latter is use, then you can filter the permalink after WP has done it's magic, but before it is used on the site. Here is an example:
function lou_rewrite_lang_in_permalink($permalink, $post, $leavename) {
// find the default post language via a function you have created to
// determine the default language url. this could be based on the current
// language the user has selected on the frontend, or based on the current
// url, or based on the post itself. it is up to you
$default_post_language = get_default_post_lang($post);
// once you have the default language, it is a simple search and replace
return str_replace('%lang%', $lang, $permalink);
}
add_filter('post_link', 'lou_rewrite_lang_in_permalink', 11, 3);
You don't mention it so I will. With your original solo function, you are gunna have a hard time if it is stand alone. The reason is because, though you have told the rewriter that a new url segment exists, you didn't tell WordPress to expect it as a url param. Thus, even though you have some fancy code to rewrite the url and tell WordPress the fancy lang param, WordPress does not know that it should be looking for it, and thus ignores it. You need to add something like this to rectify that:
function lou_add_lang_query_var($vars) {
// tell WP to expect the lang query_var, which you can then later use
$vars[] = 'lang';
// return the new list of query vars, which includes our lang param
return array_unique($vars);
}
add_filter('query_vars', 'lou_add_lang_query_var', 10, 1);
This will tell the WP() class that it needs to accept the 'lang' instead of just skipping over it. Then later you can do something like this to figure out that the current page sent as it's language:
function lou_somefunction() {
// do stuff
...
// access the $wp object
global $wp;
// determine the language from the query_vars of the current page
$lang = $wp->query_var['lang'];
// do other stuff with $lang
...
}
Hope this helps.
EDIT
First I want to say, this is an absolute travesty that language urls are not natively supported by WordPress. I have honestly never needed to do this, but most of my clients are not international companies, with international needs. I will be submitting something to WordPress in code form to solve this in a later version, but as of now, you will need a plugin like the one I have created below.
So I did a lot of investigation to make this happen. After a short conversation with the questioner, if found that my solution was incomplete. Naturally, I started digging. What seems like it should be an otherwise mediocre task, has turned out to be a VERY-not-mediocre task. The short version is, WordPress simply does not want you to insert extra parts of the url, in the middle or beginning of the url, on every url. You can easily do this with post urls ONLY with the above code, but anything more (pages, attachments, author pages, etc...) you must do something special. You can also add parts to the end of the url (endpoints), but even that is complicated.
I have worked with the WordPress rewriter extensively in the past and present, and I have what is considered Expert knowledge on the topic. Despite that, it still took me 4-5 hours to write something that will allow you to prepend a language indicator to all urls, that can then later be used to determine what language the page should be displayed in, regardless of page type. There is one catch, that I think is acceptable. You must know and specify exactly what language prefixes you want to support. I don't foresee this as a problem for anyone who would make use of this, but none-the-less, it is a limitation, simply because of the way that the rewrite engine works.
At long last, here is a plugin that you can use to accomplish this. I works on a barebone WP install, with a WooTheme as the theme. If you have other third party plugins installed, there is a possibility that this will not work for all their urls, depending on how they added their rewrite rules. In the short term, I will probably be converting this to a plugin for WP, and getting it up on Wordpress.org, but that is several days away, at least. Here is a working prototype of the code in plugin form. Create a new directory in your plugins folder (something like /wp-content/plugins/lou-lang), and then paste this code in a php file inside that folder (something like /wp-content/plugins/lou-lang/lou-lang.php). Then activate the plugin, via your admin dashboard, which will be labeled 'Loushou Language URLs'.
CODE:
<?php (__FILE__ == $_SERVER['SCRIPT_FILENAME']) ? die(header('Location: /')) : null;
/**
* Plugin Name: Loushou Language URLs
* Plugin URI: http://quadshot.com/
* Description: Adding the ability to have language support in your frontend urls.
* Version: 0.1-beta
* Author: Loushou
* Author URI: http://quadshot.com/
*/
class lou_rewrite_takeover {
protected static $add_rules = array();
public static function pre_init() {
// debug
add_action('admin_footer-options-permalink.php', array(__CLASS__, 'qsart_rewrite_debug'));
// add rw tag
add_action('init', array(__CLASS__, 'add_directory_rewrite'));
// rw rule adds
add_filter(is_admin() ? 'setup_theme' : 'do_parse_request', array(__CLASS__, 'do_parse_request'), 0);
add_filter('post_rewrite_rules', array(__CLASS__, 'post_rewrite_rules'));
add_filter('date_rewrite_rules', array(__CLASS__, 'date_rewrite_rules'));
add_filter('root_rewrite_rules', array(__CLASS__, 'root_rewrite_rules'));
add_filter('comments_rewrite_rules', array(__CLASS__, 'comments_rewrite_rules'));
add_filter('search_rewrite_rules', array(__CLASS__, 'search_rewrite_rules'));
add_filter('author_rewrite_rules', array(__CLASS__, 'author_rewrite_rules'));
add_filter('page_rewrite_rules', array(__CLASS__, 'page_rewrite_rules'));
add_filter('rewrite_rules_array', array(__CLASS__, 'final_rules_correction'), PHP_INT_MAX, 1);
// query vars
add_filter('query_vars', array(__CLASS__, 'add_lang_query_var'), 10, 1);
add_filter('request', array(__CLASS__, 'default_language'), 9);
// fix permalinks
$link_filters_needing_rewrite = array(
'post_link',
'post_type_link',
'page_link',
'attachment_link',
'search_link',
'post_type_archive_link',
'year_link',
'month_link',
'day_link',
'feed_link',
'author_link',
'term_link',
'category_feed_link',
'term_feed_link',
'taxonomy_feed_link',
'author_feed_link',
'search_feed_link',
'post_type_archive_feed_link',
);
add_filter('pre_post_link', array(__CLASS__, 'change_permalink_structure'), 10, 3);
foreach ($link_filters_needing_rewrite as $link_filter)
add_filter($link_filter, array(__CLASS__, 'rewrite_lang_in_permalink'), 11, 3);
}
public static function do_parse_request($cur) {
self::get_page_permastruct();
self::get_author_permastruct();
self::correct_extras();
return $cur;
}
public static function get_supported_langs() {
return apply_filters('lou-get-supported-languages', array(
'en',
));
}
public static function add_directory_rewrite() {
global $wp_rewrite;
$supported_languages = self::get_supported_langs();
add_rewrite_tag('%lang%', '('.implode('|', $supported_languages).')');
}
public static function unleadingslashit($str) {
return ltrim($str, '/');
}
public static function final_rules_correction($rules) {
global $wp_rewrite;
$new_rules = array();
$supported_languages = self::get_supported_langs();
$find = implode('|', $supported_languages);
$find_find = '#(?<!\()('.preg_quote($find, '#').')#';
$preg_node = str_replace('%%%', '(\d+)', preg_quote($wp_rewrite->preg_index('%%%'), '#'));
foreach ($rules as $k => $v) {
if (preg_match($find_find, $k)) {
$nk = preg_replace($find_find, '('.$find.')', $k);
$parts = explode('?', $v);
$index = array_shift($parts);
$pv = implode('?', $parts);
$pv = preg_replace_callback('#'.$preg_node.'#', function ($matches) use ($wp_rewrite) {
return $wp_rewrite->preg_index($matches[1]+1);
}, $pv);
$nv = $index.'?lang='.$wp_rewrite->preg_index(1).(!empty($pv) ? '&'.$pv : '');
$new_rules[$nk] = $nv;
} else {
$new_rules[$k] = $v;
}
}
return $new_rules;
}
public static function change_permalink_structure($struct) {
$struct = self::unleadingslashit($struct);
$struct = preg_replace('#^%lang%/?#', '', $struct);
return '/%lang%/'.$struct;
}
public static function extras_rewrite_rules($rules, $struct) {
global $wp_rewrite;
if ( is_array( $struct ) ) {
if ( count( $struct ) == 2 )
$new_rules = $wp_rewrite->generate_rewrite_rules( self::change_permalink_structure($struct[0]), $struct[1] );
else
$new_rules = $wp_rewrite->generate_rewrite_rules( self::change_permalink_structure($struct['struct']), $struct['ep_mask'], $struct['paged'], $struct['feed'], $struct['forcomments'], $struct['walk_dirs'], $struct['endpoints'] );
} else {
$new_rules = $wp_rewrite->generate_rewrite_rules( self::change_permalink_structure($struct) );
}
return $new_rules + $rules;
}
public static function post_rewrite_rules($rules) {
global $wp_rewrite;
// hack to add code for extras type urls (usually created by other plugins)
$func = array(__CLASS__, 'extras_rewrite_rules');
foreach ($wp_rewrite->extra_permastructs as $type => $struct) {
$filter = ($type == 'post_tag' ? 'tag' : $type).'_rewrite_rules';
add_filter($filter, function ($rules) use ($struct, $func) { return call_user_func_array($func, array($rules, $struct)); });
}
return $wp_rewrite->generate_rewrite_rules( self::change_permalink_structure($wp_rewrite->permalink_structure), EP_PERMALINK ) + $rules;
}
public static function date_rewrite_rules($rules) {
global $wp_rewrite;
return $wp_rewrite->generate_rewrite_rules( self::change_permalink_structure($wp_rewrite->get_date_permastruct()), EP_DATE) + $rules;
}
public static function root_rewrite_rules($rules) {
global $wp_rewrite;
return $wp_rewrite->generate_rewrite_rules( self::change_permalink_structure($wp_rewrite->get_date_permastruct()), EP_DATE) + $rules;
}
public static function comments_rewrite_rules($rules) {
global $wp_rewrite;
return $wp_rewrite->generate_rewrite_rules( self::change_permalink_structure($wp_rewrite->root . $wp_rewrite->comments_base), EP_COMMENTS, false, true, true, false) + $rules;
}
public static function search_rewrite_rules($rules) {
global $wp_rewrite;
return $wp_rewrite->generate_rewrite_rules( self::change_permalink_structure($wp_rewrite->get_search_permastruct()), EP_SEARCH) + $rules;
}
public static function author_rewrite_rules($rules) {
global $wp_rewrite;
return $wp_rewrite->generate_rewrite_rules( self::change_permalink_structure($wp_rewrite->get_author_permastruct()), EP_AUTHORS) + $rules;
}
public static function page_rewrite_rules($rules) {
global $wp_rewrite;
$page_structure = self::get_page_permastruct();
return $wp_rewrite->generate_rewrite_rules( $page_structure, EP_PAGES, true, true, false, false ) + $rules;
}
protected static function get_page_permastruct() {
global $wp_rewrite;
if (empty($wp_rewrite->permalink_structure)) {
$wp_rewrite->page_structure = '';
return false;
}
$wp_rewrite->page_structure = self::change_permalink_structure($wp_rewrite->root . '%pagename%');
return $wp_rewrite->page_structure;
}
protected static function get_author_permastruct() {
global $wp_rewrite;
if ( empty($wp_rewrite->permalink_structure) ) {
$wp_rewrite->author_structure = '';
return false;
}
$wp_rewrite->author_structure = self::change_permalink_structure($wp_rewrite->front . $wp_rewrite->author_base . '/%author%');
return $wp_rewrite->author_structure;
}
protected static function correct_extras() {
global $wp_rewrite;
foreach ($wp_rewrite->extra_permastructs as $k => $v)
$wp_rewrite->extra_permastructs[$k]['struct'] = self::change_permalink_structure($v['struct']);
}
public static function get_default_post_lang($post) {
return ( $lang = get_query_var('lang') ) ? $lang : 'en';
}
public static function rewrite_lang_in_permalink($permalink, $post=0, $leavename=false) {
// find the default post language via a function you have created to
// determine the default language url. this could be based on the current
// language the user has selected on the frontend, or based on the current
// url, or based on the post itself. it is up to you
$lang = self::get_default_post_lang($post);
// once you have the default language, it is a simple search and replace
return str_replace('%lang%', $lang, $permalink);
}
public static function add_lang_query_var($vars) {
// tell WP to expect the lang query_var, which you can then later use
$vars[] = 'lang';
// return the new list of query vars, which includes our lang param
return array_unique($vars);
}
public static function default_language($vars) {
if (array_diff( array_keys($vars), array('preview', 'page', 'paged', 'cpage') ))
$vars['lang'] = !empty($vars['lang']) ? $vars['lang'] : 'en';
return $vars;
}
public static function qsart_rewrite_debug() {
if (isset($_COOKIE['rwdebug']) && $_COOKIE['rwdebug'] == 1) {
global $wp_rewrite;
echo '<pre style="background-color:#ffffff; font-size:10px;">';
print_r($wp_rewrite->rules);
echo '</pre>';
}
}
}
if (defined('ABSPATH') && function_exists('add_action')) {
lou_rewrite_takeover::pre_init();
}
By default, the only language code supported by this plugin is 'en'. Obviously you need more than just that. Thus, once you have installed the plugin, you can add some code to your <theme>/functions.php file that looks something like this, to add the remainders.
function more_languages($list) {
$my_languages = array(
'de', 'zh', 'bg', 'fr'
);
return array_unique($list + $my_languages);
}
add_filter('lou-get-supported-languages', 'more_languages', 10, 1);
Once you have both installed the plugin and defined your custom languages, then you have one final step. You must save your permalinks. To do this from the admin, go to: Settings -> Permalinks -> Save Changes (button). After all of this, you should be good to go!
Hopefully this helps someone, and hopefully I can block out some time to get this up on wp.org.
The question is old but.. I was working on a lightweight solution for multi-language site and i came across the same problem. There is no easy way to do it with built-in WordPress functions. However (like mentioned by user1254824) there is a really easy trick to achieve it.
You can intercept the $_SERVER['REQUEST_URI'] global var, extract the /lang/ part and remove it before WordPress parsing. WordPress will serve you the regular page, but now you have your lang parameter in a var.
function localization_uri_process() {
global $lang; // then you can access $lang value in your theme's files
if( preg_match("%\A/([a-z]{2})/%", $_SERVER['REQUEST_URI'], $matches) ){
$lang = $matches[1];
$_SERVER['REQUEST_URI'] = preg_replace("%\A/[a-z]{2}/%", '/', $_SERVER['REQUEST_URI'] );
}
else
$lang = 'en'; // your default language
}
add_action( 'plugins_loaded', 'localization_uri_process' );
Then, you can also use filters to automatically rewrite all your links.
PS : The code need to be in a plugin. It won't work in your template php files.
I stumbled across this post while looking for a solution to put a language tag in front of the url path. While the wp_rewrite-solution is pretty much solid it kind of didn't work for my purpose (e.g. not having the language tag in front for the default language etc.).
So I took a closer look at the qTranslate-plugin and after I while I figured out that it uses a very simple and elegant solution:
Basically it does two things:
(Obviously) It changes all the Wordpress generated links (e.g. post_link, post_type_link, page_link etc.) to include the correct language tag in the url.
Instead of manipulating complex rewrite rules to have wordpress accept and correctly handle the language tag, it just hooks into "plugins_loaded" (that's right before Wordpress tries to parse the request) and manipulates $_SERVER['REQUEST_URI'] by cleaning out the language tag.
So if you e.g. call www.example.com/en/myurlpath Wordpress only "sees" www.example.com/myurlpath.
$_SERVER['REQUEST_URI'] = "/en/myurlpath" before the manipulation.
$_SERVER['REQUEST_URI'] = "/myurlpath" after the manipulation.
This way your only "job" is to clean up any urls before Wordpress is parsing them.

Wordpress match url for custom content without post or page

Im new in wordpress.
I want to use two tables and display some content without creating pages or posts.
The matched url will be something like this:
/[category]/[image] - /nature/green-tree
My method was to check the url in index.php from theme and split the url and create a mini route system just for the gallery. But I think it is not the smartest idea.
I don't want to use gallery plugins because I'm already using one, and this is a change that I need to to.
What is the best method to do this?
I suppose you need custom rewrite rules. Here is how you can do it by yourself.
If you are using a theme then open the functions.php file and enter the following code, otherwise if you are using a plugin, place this code somewhere in your plugin, but make sure, that it is loading immediately.
function registerCustomUrl($rewrite)
{
$rewrites = $rewrite->rules;
$newRewrites = array();
$newRewrites['([^/]+)/([^/]+)/?$'] = 'index.php?gallery_category=$matches[1]&gallery_image=$matches[2]';
foreach($rewrites as $rk => $rv)
{
$newRewrites[$rk] = $rv;
}
$rewrite->rules = $newRewrites;
}
add_action('generate_rewrite_rules', 'registerCustomUrl');
function registerCustomQueryVars( $vars ) {
$vars[] = 'gallery_category';
$vars[] = 'gallery_image';
return $vars;
}
add_filter('query_vars', 'registerCustomQueryVars');
function myCustomTemplateRedirect()
{
global $wp_query;
if(
isset($wp_query->query_vars['gallery_category']) &&
!empty($wp_query->query_vars['gallery_category']) &&
isset($wp_query->query_vars['gallery_image']) &&
!empty($wp_query->query_vars['gallery_image'])
)
{
// Within your custom template file you are able to
// use any theme function like the get_header(), get_footer(), etc
require_once('path/to/your/custom/template/file.php');
exit(0);
}
}
add_action("template_redirect", 'myCustomTemplateRedirect');

Problem return a function inside of a shortcode in Wordpress

I have some trouble coding a themes shortcode. I want the code to display a div with a view counter function, and then a link with the shotcodes content as the url.
The view_count(); function works fine when called inside theme files, and I actually managed to make it show, but then it displayed before the_content(); of the post (the gray bar), when I wanted it within content under an element.
(1) Here's what I've got:
function video_block( $atts, $content = null ) {
return '<div class="video-block"><span class="ViewCount"><?php the_views(); ?></span> <a class="dl-source" href="' . $content . '">Link</a></div>';
}
(2) Here's the code that displays both on top of page:
function video_block( $atts, $content = null ) { ?>
<div class="video-block"><span class="ViewCount"><?php the_views(); ?></span> <a class="dl-source" href="<?php echo $content; ?>">Link</a></div>
<?php }
(3) This code displays the views above content, and the link in the correct place:
function video_block( $atts, $content = null ) {
$views = the_views();
return '<div class="video-block"><span class="ViewCount"><?php $views; ?></span> <a class="dl-source" href="<?php echo $content; ?>">Link</a></div>';
}
I read somewhere in the Wordpress forums that you should return (instead of echo) values within functions, but that breaks it, displaying the view count, skips the html and spits out the $content.
Here is a link to the page in question: http://nvrt.me/4Qf1 (currently using code from block #2)
I'm running out of midnight oil. I would really appreciate it if someone could help me out.
EDIT:
Here is the code for the_views(); function. I can see that it's echoed, but when changed to return, it doesn't display it at all.
### Function: Display The Post Views
function the_views($display = true, $prefix = '', $postfix = '', $always = false) {
$post_views = intval(post_custom('views'));
$views_options = get_option('views_options');
if ($always || should_views_be_displayed($views_options)) {
$output = $prefix.str_replace('%VIEW_COUNT%', number_format_i18n($post_views), $views_options['template']).$postfix;
if($display) {
echo apply_filters('the_views', $output);
} else {
return apply_filters('the_views', $output);
}
}
elseif (!$display) {
return '';
}
}
Even though it is a recommended practice in Wordpress to have functions that return values, it is not always possible, especially when you are calling another function that writes it's output directly to the stream.
When the component writes it's output directly to the stream you need to code to accommodate that behavior unless you want to rewrite the who component (I wouldn't do that ;-) ).
In this instance the the_views() function actually offers you both options. If you look at the $display parameter and follow the code this function can behave both ways. If $display is set to True (it's default) it will echo the results of the function. If $display is set to False it will return the output.
So you have two options, both of which should work:
Option 1, Return a value
Note that when I call the_views() I pass it a false parameter like this: the_views(false)
<?php
function video_block( $atts, $content = null ) {
return "<div class=\"video-block\"><span class=\"ViewCount\">" . the_views(false) . "</span><a class=\"dl-source\" href=\"$content\">Link</a></div>";
}
?>
*Option 2: Echo your output *
Note that when I call the the_views() there are no parameters passed to it.
<?php
function video_block( $atts, $content = null ) {
echo "<div class=\"video-block\"><span class=\"ViewCount\">";
the_views();
echo "</span><a class=\"dl-source\" href=\"$content\">Link</a></div>";
}
?>
Oh, also, don't forget to escape your quotes when you are returning a string.
Couldn't add the code block as a comment on #BLewis response but working off what he said, I did something like this:
function my_shortcode() {
ob_start();
a_function_to_display();
$data = ob_get_clean();
return $data;
}
add_shortcode( 'shortcode_name', 'my_shortcode' );
I'd like to contribute a new answer here.
I was working on extending a plugin and found this was how the author did it and to me it makes much more sense.
If you're outputting a lot of HTML you should not use echo, it's bad practise, hard to read and a pain to keep the formatting of the output nice using echo. Even if you use it's counter parts, it's still less clean to have echo_r or print or var_dump than to use pure HTML.
Since PHP only runs inside the wrapper tags <?php and ?>, you should use this to your advantage.
But since we can't just do this here because you may lose your content order, you can use some object storing. Basically before you start your HTML block (probably at the beginning of your shortcode function would be good), just add ob_start(); to store your code. Then just before ending your function, you can return your data using $data = ob_get_clean(); and return $data; .
Good luck with more WordPress work.

Output content from wordpress plugin and rewrite rules

I have created a wordpress plugin that has a filter on the_content, looking for a specific tag then outputting the plugin content in place of that tag.
I would now like to use rewrite rules to call the plugin and output the data within the template, but I'm not finding much help.
Can someone provide an example, or some guidance on how to add a rewrite rule using the built in wp methods and calling my methods in the plugin which outputs some content.
Ideally, I would like shop/ to be matched and then pass everything after shop to my dispatch method on my plugin so that I can have shop/category/shirts or shop/product/the-cool-shirt. My dispatch method would handle breaking apart the rest of the url and calling methods accordingly.
This can get rather interesting. I had to do this for a plugin at one point, I don't have it in front of me, so this it out of memory, but the general idea should be correct.
<?php
add_action('init', 'rewrite_rules');
function rewrite_rules() {
global $wp, $wp_rewrite;
$wp_rewrite->add_rule('(widget1|widget2|widget3)/([a-zA-Z0-9_-]{3,50})$', 'index.php?pagename=listing&category=$matches[1]&subcategory=$matches[2]', 'top' );
$wp->add_query_var( 'category' );
$wp->add_query_var( 'subcategory' );
$wp_rewrite->flush_rules();
}
?>
Using regular expressions is a monumental task in itself, I believe I used this site: http://tools.netshiftmedia.com/regexlibrary/ for help.
I also used FakePage plugin to actually display my custom "dynamic" pages, as I called them, but I suppose everything in WP is technically dynamic.
http://scott.sherrillmix.com/blog/blogger/creating-a-better-fake-post-with-a-wordpress-plugin/
Let me know if you need more help.
I did something very similar not long ago, and I did it by cheating.
If you find the built in rewrite rules too complicated or unable to do the job, you may find it easier to catch the request and filter the results. A simplified version:
add_action('parse_request', 'my_parse_request');
function my_parse_request (&$wp) {
$path = $wp->request;
$groups = array();
if (preg_match("%shop/product/([a-zA-Z0-9-]+)%", $path, $groups)) {
$code = $groups[1];
$product = get_product($code); // your own code here
if (isset($product)) {
add_filter('the_posts', 'my_product_filter_posts');
}
}
}
function my_product_filter_posts ($posts) {
ob_start();
echo "stuff goes here"; // your body here
$content = ob_get_contents();
ob_end_clean();
return array(new DummyResult(0, "Product name", $content));
}
To explain:
The action on parse_request is called before the database lookup. Based on the URL, it installs the other actions and filters.
The filter on posts replaces the results of the database lookup with fake results.
DummyResult is a simple class that has the same fields as a post, or just enough of them to get away with it:
class DummyResult {
public $ID;
public $post_title;
public $post_content;
public $post_author;
public $comment_status = "closed";
public $post_status = "publish";
public $ping_status = "closed";
public $post_type = "page";
public $post_date = "";
function __construct ($ID, $title, $content) {
$this->ID = $ID;
$this->post_title = $title;
$this->post_content = $content;
$this->post_author = get_default_author(); // implement this function
}
}
There's a lot of homework left for the reader in the above, but it's an ugly, working approach. You'll probably want to add a filter for template_redirect, to replace the normal page template with a product-specific one. And you may need to adjust the URL regex if you want pretty permalinks.

Categories