Title: wp_video_shortcode
Published: April 25, 2014
Last modified: August 20, 2026

---

# wp_video_shortcode( array $attr, string $content = '' ): string|null

## In this article

 * [Description](https://developer.wordpress.org/reference/functions/wp_video_shortcode/?output_format=md#description)
 * [Parameters](https://developer.wordpress.org/reference/functions/wp_video_shortcode/?output_format=md#parameters)
 * [Return](https://developer.wordpress.org/reference/functions/wp_video_shortcode/?output_format=md#return)
 * [Source](https://developer.wordpress.org/reference/functions/wp_video_shortcode/?output_format=md#source)
 * [Hooks](https://developer.wordpress.org/reference/functions/wp_video_shortcode/?output_format=md#hooks)
 * [Related](https://developer.wordpress.org/reference/functions/wp_video_shortcode/?output_format=md#related)
 * [Changelog](https://developer.wordpress.org/reference/functions/wp_video_shortcode/?output_format=md#changelog)
 * [User Contributed Notes](https://developer.wordpress.org/reference/functions/wp_video_shortcode/?output_format=md#user-contributed-notes)

[ Back to top](https://developer.wordpress.org/reference/functions/wp_video_shortcode/?output_format=md#wp--skip-link--target)

Builds the Video shortcode output.

## 󠀁[Description](https://developer.wordpress.org/reference/functions/wp_video_shortcode/?output_format=md#description)󠁿

This implements the functionality of the Video Shortcode for displaying WordPress
mp4s in a post.

## 󠀁[Parameters](https://developer.wordpress.org/reference/functions/wp_video_shortcode/?output_format=md#parameters)󠁿

 `$attr`arrayrequired

Attributes of the shortcode.

 * `src` string
 * URL to the source of the video file. Default empty.
 * `height` int
 * Height of the video embed in pixels. Default 360.
 * `width` int
 * Width of the video embed in pixels. Default $content_width or 640.
 * `poster` string
 * The `'poster'` attribute for the `<video>` element. Default empty.
 * `loop` string
 * The `'loop'` attribute for the `<video>` element. Default empty.
 * `autoplay` string
 * The `'autoplay'` attribute for the `<video>` element. Default empty.
 * `muted` string
 * The `'muted'` attribute for the `<video>` element. Default false.
 * `preload` string
 * The `'preload'` attribute for the `<video>` element.
    Default `'metadata'`.
 * `class` string
 * The `'class'` attribute for the `<video>` element.
    Default `'wp-video-shortcode'`.

`$content`stringoptional

Shortcode content.

Default:`''`

## 󠀁[Return](https://developer.wordpress.org/reference/functions/wp_video_shortcode/?output_format=md#return)󠁿

 string|null HTML content to display video.

## 󠀁[Source](https://developer.wordpress.org/reference/functions/wp_video_shortcode/?output_format=md#source)󠁿

    ```php
    function wp_video_shortcode( $attr, $content = '' ) {
    	global $content_width;
    	$post_id = get_post() ? get_the_ID() : 0;

    	static $instance = 0;
    	++$instance;

    	/**
    	 * Filters the default video shortcode output.
    	 *
    	 * If the filtered output isn't empty, it will be used instead of generating
    	 * the default video template.
    	 *
    	 * @since 3.6.0
    	 *
    	 * @see wp_video_shortcode()
    	 *
    	 * @param string $html     Empty variable to be replaced with shortcode markup.
    	 * @param array  $attr     Attributes of the shortcode. See wp_video_shortcode().
    	 * @param string $content  Video shortcode content.
    	 * @param int    $instance Unique numeric ID of this video shortcode instance.
    	 */
    	$override = apply_filters( 'wp_video_shortcode_override', '', $attr, $content, $instance );

    	if ( '' !== $override ) {
    		return $override;
    	}

    	$video = null;

    	$default_types = wp_get_video_extensions();
    	$defaults_atts = array(
    		'src'      => '',
    		'poster'   => '',
    		'loop'     => '',
    		'autoplay' => '',
    		'muted'    => 'false',
    		'preload'  => 'metadata',
    		'width'    => 640,
    		'height'   => 360,
    		'class'    => 'wp-video-shortcode',
    	);

    	foreach ( $default_types as $type ) {
    		$defaults_atts[ $type ] = '';
    	}

    	$atts = shortcode_atts( $defaults_atts, $attr, 'video' );

    	if ( is_admin() ) {
    		// Shrink the video so it isn't huge in the admin.
    		if ( $atts['width'] > $defaults_atts['width'] ) {
    			$atts['height'] = round( ( $atts['height'] * $defaults_atts['width'] ) / $atts['width'] );
    			$atts['width']  = $defaults_atts['width'];
    		}
    	} else {
    		// If the video is bigger than the theme.
    		if ( ! empty( $content_width ) && $atts['width'] > $content_width ) {
    			$atts['height'] = round( ( $atts['height'] * $content_width ) / $atts['width'] );
    			$atts['width']  = $content_width;
    		}
    	}

    	$is_vimeo      = false;
    	$is_youtube    = false;
    	$yt_pattern    = '#^https?://(?:www\.)?(?:youtube\.com/watch|youtu\.be/)#';
    	$vimeo_pattern = '#^https?://(.+\.)?vimeo\.com/.*#';

    	$primary = false;
    	if ( ! empty( $atts['src'] ) ) {
    		$is_vimeo   = ( preg_match( $vimeo_pattern, $atts['src'] ) );
    		$is_youtube = ( preg_match( $yt_pattern, $atts['src'] ) );

    		if ( ! $is_youtube && ! $is_vimeo ) {
    			$type = wp_check_filetype( $atts['src'], wp_get_mime_types() );

    			if ( ! in_array( strtolower( $type['ext'] ), $default_types, true ) ) {
    				return sprintf( '<a class="wp-embedded-video" href="%s">%s</a>', esc_url( $atts['src'] ), esc_html( $atts['src'] ) );
    			}
    		}

    		if ( $is_vimeo ) {
    			wp_enqueue_script( 'mediaelement-vimeo' );
    		}

    		$primary = true;
    		array_unshift( $default_types, 'src' );
    	} else {
    		foreach ( $default_types as $ext ) {
    			if ( ! empty( $atts[ $ext ] ) ) {
    				$type = wp_check_filetype( $atts[ $ext ], wp_get_mime_types() );
    				if ( strtolower( $type['ext'] ) === $ext ) {
    					$primary = true;
    				}
    			}
    		}
    	}

    	if ( ! $primary ) {
    		$videos = get_attached_media( 'video', $post_id );
    		if ( empty( $videos ) ) {
    			return null;
    		}

    		$video       = reset( $videos );
    		$atts['src'] = wp_get_attachment_url( $video->ID );
    		if ( empty( $atts['src'] ) ) {
    			return null;
    		}

    		array_unshift( $default_types, 'src' );
    	}

    	/**
    	 * Filters the media library used for the video shortcode.
    	 *
    	 * @since 3.6.0
    	 *
    	 * @param string $library Media library used for the video shortcode.
    	 */
    	$library = apply_filters( 'wp_video_shortcode_library', 'mediaelement' );
    	if ( 'mediaelement' === $library && did_action( 'init' ) ) {
    		wp_enqueue_style( 'wp-mediaelement' );
    		wp_enqueue_script( 'wp-mediaelement' );
    		wp_enqueue_script( 'mediaelement-vimeo' );
    	}

    	/*
    	 * MediaElement.js has issues with some URL formats for Vimeo and YouTube,
    	 * so update the URL to prevent the ME.js player from breaking.
    	 */
    	if ( 'mediaelement' === $library ) {
    		if ( $is_youtube ) {
    			// Remove `feature` query arg and force SSL - see #40866.
    			$atts['src'] = remove_query_arg( 'feature', $atts['src'] );
    			$atts['src'] = set_url_scheme( $atts['src'], 'https' );
    		} elseif ( $is_vimeo ) {
    			// Remove all query arguments and force SSL - see #40866.
    			$parsed_vimeo_url = wp_parse_url( $atts['src'] );
    			$vimeo_src        = 'https://' . $parsed_vimeo_url['host'] . $parsed_vimeo_url['path'];

    			// Add loop param for mejs bug - see #40977, not needed after #39686.
    			$loop        = $atts['loop'] ? '1' : '0';
    			$atts['src'] = add_query_arg( 'loop', $loop, $vimeo_src );
    		}
    	}

    	/**
    	 * Filters the class attribute for the video shortcode output container.
    	 *
    	 * @since 3.6.0
    	 * @since 4.9.0 The `$atts` parameter was added.
    	 *
    	 * @param string $class CSS class or list of space-separated classes.
    	 * @param array  $atts  Array of video shortcode attributes.
    	 */
    	$atts['class'] = apply_filters( 'wp_video_shortcode_class', $atts['class'], $atts );

    	$html_atts = array(
    		'class'    => $atts['class'],
    		'id'       => sprintf( 'video-%d-%d', $post_id, $instance ),
    		'width'    => absint( $atts['width'] ),
    		'height'   => absint( $atts['height'] ),
    		'poster'   => esc_url( $atts['poster'] ),
    		'loop'     => wp_validate_boolean( $atts['loop'] ),
    		'autoplay' => wp_validate_boolean( $atts['autoplay'] ),
    		'muted'    => wp_validate_boolean( $atts['muted'] ),
    		'preload'  => $atts['preload'],
    	);

    	// These ones should just be omitted altogether if they are blank.
    	foreach ( array( 'poster', 'loop', 'autoplay', 'preload', 'muted' ) as $a ) {
    		if ( empty( $html_atts[ $a ] ) ) {
    			unset( $html_atts[ $a ] );
    		}
    	}

    	$attr_strings = array();
    	foreach ( $html_atts as $attribute_name => $attribute_value ) {
    		if ( in_array( $attribute_name, array( 'loop', 'autoplay', 'muted' ), true ) && true === $attribute_value ) {
    			// Add boolean attributes without their value for true.
    			$attr_strings[] = esc_attr( $attribute_name );
    		} elseif ( 'preload' === $attribute_name && ! empty( $attribute_value ) ) {
    			// Handle the preload attribute with specific allowed values.
    			$allowed_preload_values = array( 'none', 'metadata', 'auto' );
    			if ( in_array( $attribute_value, $allowed_preload_values, true ) ) {
    				$attr_strings[] = sprintf( '%s="%s"', esc_attr( $attribute_name ), esc_attr( $attribute_value ) );
    			}
    		} elseif ( ! empty( $attribute_value ) ) {
    			// For non-boolean attributes, add them with their value.
    			$attr_strings[] = sprintf( '%s="%s"', esc_attr( $attribute_name ), esc_attr( $attribute_value ) );
    		}
    	}

    	$html    = sprintf( '<video %s controls="controls">', implode( ' ', $attr_strings ) );
    	$fileurl = '';
    	$source  = '<source type="%s" src="%s" />';

    	foreach ( $default_types as $fallback ) {
    		if ( ! empty( $atts[ $fallback ] ) ) {
    			if ( empty( $fileurl ) ) {
    				$fileurl = $atts[ $fallback ];
    			}
    			if ( 'src' === $fallback && $is_youtube ) {
    				$type = array( 'type' => 'video/youtube' );
    			} elseif ( 'src' === $fallback && $is_vimeo ) {
    				$type = array( 'type' => 'video/vimeo' );
    			} else {
    				$type = wp_check_filetype( $atts[ $fallback ], wp_get_mime_types() );
    			}
    			$url   = add_query_arg( '_', $instance, $atts[ $fallback ] );
    			$html .= sprintf( $source, $type['type'], esc_url( $url ) );
    		}
    	}

    	if ( ! empty( $content ) ) {
    		if ( str_contains( $content, "\n" ) ) {
    			$content = str_replace( array( "\r\n", "\n", "\t" ), '', $content );
    		}
    		$html .= trim( $content );
    	}

    	if ( 'mediaelement' === $library ) {
    		$html .= wp_mediaelement_fallback( $fileurl );
    	}
    	$html .= '</video>';

    	$width_rule = '';
    	if ( ! empty( $atts['width'] ) ) {
    		$width_rule = sprintf( 'width: %dpx;', $atts['width'] );
    	}
    	$output = sprintf( '<div style="%s" class="wp-video">%s</div>', $width_rule, $html );

    	/**
    	 * Filters the output of the video shortcode.
    	 *
    	 * @since 3.6.0
    	 *
    	 * @param string $output  Video shortcode HTML output.
    	 * @param array  $atts    Array of video shortcode attributes.
    	 * @param string $video   Video file.
    	 * @param int    $post_id Post ID.
    	 * @param string $library Media library used for the video shortcode.
    	 */
    	return apply_filters( 'wp_video_shortcode', $output, $atts, $video, $post_id, $library );
    }
    ```

[View all references](https://developer.wordpress.org/reference/files/wp-includes/media.php/)
[View on Trac](https://core.trac.wordpress.org/browser/tags/7.1/src/wp-includes/media.php#L3759)
[View on GitHub](https://github.com/WordPress/wordpress-develop/blob/7.1/src/wp-includes/media.php#L3759-L4004)

## 󠀁[Hooks](https://developer.wordpress.org/reference/functions/wp_video_shortcode/?output_format=md#hooks)󠁿

 [apply_filters( ‘wp_video_shortcode’, string $output, array $atts, string $video, int $post_id, string $library )](https://developer.wordpress.org/reference/hooks/wp_video_shortcode/)

Filters the output of the video shortcode.

 [apply_filters( ‘wp_video_shortcode_class’, string $class, array $atts )](https://developer.wordpress.org/reference/hooks/wp_video_shortcode_class/)

Filters the class attribute for the video shortcode output container.

 [apply_filters( ‘wp_video_shortcode_library’, string $library )](https://developer.wordpress.org/reference/hooks/wp_video_shortcode_library/)

Filters the media library used for the video shortcode.

 [apply_filters( ‘wp_video_shortcode_override’, string $html, array $attr, string $content, int $instance )](https://developer.wordpress.org/reference/hooks/wp_video_shortcode_override/)

Filters the default video shortcode output.

## 󠀁[Related](https://developer.wordpress.org/reference/functions/wp_video_shortcode/?output_format=md#related)󠁿

| Uses | Description | 
| [wp_parse_url()](https://developer.wordpress.org/reference/functions/wp_parse_url/)`wp-includes/http.php` |

A wrapper for PHP’s parse_url() function that handles consistency in the return values across PHP versions.

  | 
| [wp_validate_boolean()](https://developer.wordpress.org/reference/functions/wp_validate_boolean/)`wp-includes/functions.php` |

Filters/validates a variable as a boolean.

  | 
| [wp_check_filetype()](https://developer.wordpress.org/reference/functions/wp_check_filetype/)`wp-includes/functions.php` |

Retrieves the file type from the file name.

  | 
| [wp_get_mime_types()](https://developer.wordpress.org/reference/functions/wp_get_mime_types/)`wp-includes/functions.php` |

Retrieves the list of mime types and file extensions.

  | 
| [remove_query_arg()](https://developer.wordpress.org/reference/functions/remove_query_arg/)`wp-includes/functions.php` |

Removes an item or items from a query string.

  | 
| [set_url_scheme()](https://developer.wordpress.org/reference/functions/set_url_scheme/)`wp-includes/link-template.php` |

Sets the scheme for a URL.

  | 
| [shortcode_atts()](https://developer.wordpress.org/reference/functions/shortcode_atts/)`wp-includes/shortcodes.php` |

Combines user attributes with known attributes and fill in defaults when needed.

  | 
| [did_action()](https://developer.wordpress.org/reference/functions/did_action/)`wp-includes/plugin.php` |

Retrieves the number of times an action has been fired during the current request.

  | 
| [get_the_ID()](https://developer.wordpress.org/reference/functions/get_the_id/)`wp-includes/post-template.php` |

Retrieves the ID of the current item in the WordPress Loop.

  | 
| [get_attached_media()](https://developer.wordpress.org/reference/functions/get_attached_media/)`wp-includes/media.php` |

Retrieves media attached to the passed post.

  | 
| [wp_get_video_extensions()](https://developer.wordpress.org/reference/functions/wp_get_video_extensions/)`wp-includes/media.php` |

Returns a filtered list of supported video formats.

  | 
| [wp_mediaelement_fallback()](https://developer.wordpress.org/reference/functions/wp_mediaelement_fallback/)`wp-includes/media.php` |

Provides a No-JS Flash fallback as a last resort for audio / video.

  | 
| [wp_get_attachment_url()](https://developer.wordpress.org/reference/functions/wp_get_attachment_url/)`wp-includes/post.php` |

Retrieves the URL for an attachment.

  | 
| [esc_url()](https://developer.wordpress.org/reference/functions/esc_url/)`wp-includes/formatting.php` |

Checks and cleans a URL.

  | 
| [esc_html()](https://developer.wordpress.org/reference/functions/esc_html/)`wp-includes/formatting.php` |

Escaping for HTML blocks.

  | 
| [esc_attr()](https://developer.wordpress.org/reference/functions/esc_attr/)`wp-includes/formatting.php` |

Escaping for HTML attributes.

  | 
| [is_admin()](https://developer.wordpress.org/reference/functions/is_admin/)`wp-includes/load.php` |

Determines whether the current request is for an administrative interface page.

  | 
| [wp_enqueue_script()](https://developer.wordpress.org/reference/functions/wp_enqueue_script/)`wp-includes/functions.wp-scripts.php` |

Enqueues a script.

  | 
| [absint()](https://developer.wordpress.org/reference/functions/absint/)`wp-includes/load.php` |

Converts a value to non-negative integer.

  | 
| [add_query_arg()](https://developer.wordpress.org/reference/functions/add_query_arg/)`wp-includes/functions.php` |

Retrieves a modified URL query string.

  | 
| [wp_enqueue_style()](https://developer.wordpress.org/reference/functions/wp_enqueue_style/)`wp-includes/functions.wp-styles.php` |

Enqueues a CSS stylesheet.

  | 
| [apply_filters()](https://developer.wordpress.org/reference/functions/apply_filters/)`wp-includes/plugin.php` |

Calls the callback functions that have been added to a filter hook.

  | 
| [get_post()](https://developer.wordpress.org/reference/functions/get_post/)`wp-includes/post.php` |

Retrieves post data given a post ID or post object.

  |

[Show 18 more](https://developer.wordpress.org/reference/functions/wp_video_shortcode/?output_format=md#)
[Show less](https://developer.wordpress.org/reference/functions/wp_video_shortcode/?output_format=md#)

| Used by | Description | 
| [WP_Widget_Media_Video::render_media()](https://developer.wordpress.org/reference/classes/wp_widget_media_video/render_media/)`wp-includes/widgets/class-wp-widget-media-video.php` |

Render the media on the frontend.

  | 
| [edit_form_image_editor()](https://developer.wordpress.org/reference/functions/edit_form_image_editor/)`wp-admin/includes/media.php` |

Displays the image and editor in the post editor

  | 
| [prepend_attachment()](https://developer.wordpress.org/reference/functions/prepend_attachment/)`wp-includes/post-template.php` |

Wraps attachment in paragraph tag before content.

  |

## 󠀁[Changelog](https://developer.wordpress.org/reference/functions/wp_video_shortcode/?output_format=md#changelog)󠁿

| Version | Description | 
| [3.6.0](https://developer.wordpress.org/reference/since/3.6.0/) | Introduced. |

## 󠀁[User Contributed Notes](https://developer.wordpress.org/reference/functions/wp_video_shortcode/?output_format=md#user-contributed-notes)󠁿

 1.  [Skip to note 2 content](https://developer.wordpress.org/reference/functions/wp_video_shortcode/?output_format=md#comment-content-6171)
 2.   [atpdejong](https://profiles.wordpress.org/atpdejong/)  [  4 years ago  ](https://developer.wordpress.org/reference/functions/wp_video_shortcode/#comment-6171)
 3. [You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_video_shortcode%2F%23comment-6171)
    Vote results for this note: 0[You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_video_shortcode%2F%23comment-6171)
 4. An example on how to use this function with all the attributes in an array.
 5.     ```php
        // Attributes of the shortcode.
        $attr = array(
        	'src'        => '',
        	'height'     => 360,
        	'width'      => 640,
        	'poster'     => '',
        	'loop'       => '',
        	'autoplay'   => '',
        	'muted'      => 'false',
        	'preload'    => 'metadata',
        	'class'      => 'wp-video-shortcode',
        );
    
        $content = ''; // content
    
        echo wp_video_shortcode( $attr, $content );
        ```
    
 6.  * The property muted was added since version 6.1. Autoplay does not work if the
       video is not muted.
     * [atpdejong](https://profiles.wordpress.org/atpdejong/) [4 years ago](https://developer.wordpress.org/reference/functions/wp_video_shortcode/#comment-6201)
 7.  [Log in to add feedback](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_video_shortcode%2F%3Freplytocom%3D6171%23feedback-editor-6171)

You must [log in](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_video_shortcode%2F)
before being able to contribute a note or feedback.