Validation Function for URL in plugin

I would look into PHP’s parse_url() and/or filter_var() with FILTER_VALIDATE_URL filter. parse_url() gives you a bit more control. Combine that with a sanitization as mentioned at the end.

Here are couple use cases that will hopefully give you a better idea on how to proceed:


If you want to verify that the url’s domain is of an approved site:

function url_allowed( $url ) {

        $allowed_hosts = array(
                        'youtube.com',
                        'vimeo.com'
                        ); 
        if ( in_array( parse_url( $url, PHP_URL_HOST ), $allowed_hosts ) ) {
            return true;
        }

        return false;      
    }

Then pass it the url to check within your conditional:

if ( url_allowed( $value_of_url_to_check_wherever_you_are_getting_it ) ) {
    //do stuff
}

If you just want to confirm it is a url at all (which will include ftp://, etc., btw),

if ( filter_var( $url, FILTER_VALIDATE_URL ) ) {
    //do stuff
}

If you would like to only allow urls beginning with http or https,

if ( parse_url( $url, PHP_URL_SCHEME ) == 'http' || parse_url( $url, PHP_URL_SCHEME ) == 'https' ) {
    //do stuff
}

I would also recommended sanitizing the url either via the WordPress esc_url() or php’s filter_var( $url, FILTER_SANITIZE_URL )


Edit: Using WP’s wp_parse_url()

WordPress provides a wrapper for PHP’s parse_url(): wp_parse_url(). It returns an array of 'scheme', 'host', and 'path'. Usage is the same as above:

function url_allowed( $url ) {

        $allowed_hosts = array(
                        'youtube.com',
                        'vimeo.com'
                        );
        $url_array = wp_parse_url($url); 
        if ( in_array( $url_array['host'], $allowed_hosts ) ) {
            return true;
        }

        return false;      
    }

Additionally, the WordPress function wp_allowed_protocols() returns a default list of protocols you could check against:

  array( 'http', 
         'https', 
         'ftp', 
         'ftps', 
         'mailto', 
         'news', 
         'irc', 
         'gopher', 
         'nntp', 
         'feed', 
         'telnet', 
         'mms', 
         'rtsp', 
         'svn', 
         'tel', 
         'fax', 
         'xmpp', 
         'webcal', 
         'urn' 
    )

You can filtered this list with the hook kses_allowed_protocols.
In example, removing the mailto protocol may go something like this:

add_filter( 'kses_allowed_protocols', 'my_protocols' );
function my_protocols( $protocols ) {

    if( ($key = array_search( 'mailto', $protocols ) ) !== false ) {    
        unset( $protocols[ $key ] );
    }
}

Do note that this approved protocol list is used by _links_add_base(), edit_user() (for the user url field), wp_kses(), wp_kses_one_attr(), and esc_url().

I would contend it is better to explicitly check the intended protocol of the input field rather than just checking it against this array.


A more complete usage case

Since your usage is to allow users to input urls from specific sites, and in both cases these video urls are served using protocol https, I would check for the site host and force the protocol, and use esc_url() to clean up characters.

Since the end result will require you to know whether the url is from Vimeo or YouTube, you could save that as well.

check against allowed hosts, used by url_verify()

function url_allowed_host( $host ) {

    $allowed_hosts = array(
                    'youtube.com',
                    'vimeo.com'
                    );

    if ( in_array( $host, $allowed_hosts ) ) {
        return true;
    }

    return false;      
}

parse entered url, force https, verify allowed host, create and return array of values

   function url_verify( $url ) {

        $url_array = wp_parse_url( $url );

        if ( $url_array['scheme'] !== 'https' ) {

            $url_array['scheme'] = 'https';
        }

        if ( url_allowed_host( $url_array['host'] ) ) {

            //lets ditch the .com
            $host_word = explode( '.', $url_array['host'] );

            //this should now be just "youtube" or "vimeo"
            $meta_array['host'] = $host_word;
            $meta_array['url']  = $url_array['scheme'] . $url_array['host'] . $url_array['path'];

            return $meta_array;

       } else {

        return false;

       }

   } 

Save the array with url and url host name

  add_action( 'save_post', 'my_meta_save', 10, 2 );

  function my_meta_save( $post_id, $post ) {
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
            return;
        }
    //do nonce check here

    //assuming form field is named: video-url, make sure it is set and not empty AND that url_verify did not return false
    if ( ( isset( $_POST['video-url'] ) && ! empty( $_POST['video-url'] ) ) && ( false !== url_verify( $_POST['video-url'] ) ) ) {


        update_post_meta( $post_id, 'video_url', esc_url( $POST['video_url'] ) );

    }
    //if any of the above are not true, treat it as blank and delete existing value
    else {

        delete_post_meta( $post_id, 'video-url' );
    }    


  }

Retrieve the values

$video_meta = get_post_meta( $post_id, 'video-url', false );
$url = esc_url( $video_meta['url'] );
$host = santize_text_field( $video_meta['host'] );

Displaying something conditionally per host

I use a switch here in case you have a longer list of allowed domains.

switch ( $host ) {
    case "youtube":
        //do some youtube stuff
        break;

    case "vimeo":
        //do some vimeo stuff
        break;
}

Leave a Comment