0

Please help me edit the code so that wordpress does not change the & symbol to #038 when I publish links on my site

function esc_url( $url, $protocols = null, $_context = 'display' ) {
$original_url = $url;

if ( '' === $url ) {
    return $url;
}

$url = str_replace( ' ', '%20', ltrim( $url ) );
$url = preg_replace( '|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\[\]\\x80-\\xff]|i', '', $url );

if ( '' === $url ) {
    return $url;
}

if ( 0 !== stripos( $url, 'mailto:' ) ) {
    $strip = array( '%0d', '%0a', '%0D', '%0A' );
    $url   = _deep_replace( $strip, $url );
}

$url = str_replace( ';//', '://', $url );
/*
 * If the URL doesn't appear to contain a scheme, we presume
 * it needs http:// prepended (unless it's a relative link
 * starting with /, # or ?, or a PHP file).
 */
if ( ! str_contains( $url, ':' ) && ! in_array( $url[0], array( '/', '#', '?' ), true ) &&
    ! preg_match( '/^[a-z0-9-]+?\.php/i', $url )
) {
    $url = 'http://' . $url;
}

// Replace ampersands and single quotes only when displaying.
if ( 'display' === $_context ) {
    $url = wp_kses_normalize_entities( $url );
    $url = str_replace( '&', '&', $url );
    $url = str_replace( "'", ''', $url );
}

if ( str_contains( $url, '[' ) || str_contains( $url, ']' ) ) {

    $parsed = wp_parse_url( $url );
    $front  = '';

    if ( isset( $parsed['scheme'] ) ) {
        $front .= $parsed['scheme'] . '://';
    } elseif ( '/' === $url[0] ) {
        $front .= '//';
    }

    if ( isset( $parsed['user'] ) ) {
        $front .= $parsed['user'];
    }

    if ( isset( $parsed['pass'] ) ) {
        $front .= ':' . $parsed['pass'];
    }

    if ( isset( $parsed['user'] ) || isset( $parsed['pass'] ) ) {
        $front .= '@';
    }

    if ( isset( $parsed['host'] ) ) {
        $front .= $parsed['host'];
    }

    if ( isset( $parsed['port'] ) ) {
        $front .= ':' . $parsed['port'];
    }

    $end_dirty = str_replace( $front, '', $url );
    $end_clean = str_replace( array( '[', ']' ), array( '%5B', '%5D' ), $end_dirty );
    $url       = str_replace( $end_dirty, $end_clean, $url );

}

if ( '/' === $url[0] ) {
    $good_protocol_url = $url;
} else {
    if ( ! is_array( $protocols ) ) {
        $protocols = wp_allowed_protocols();
    }
    $good_protocol_url = wp_kses_bad_protocol( $url, $protocols );
    if ( strtolower( $good_protocol_url ) !== strtolower( $url ) ) {
        return '';
    }
}
0

1 Answer 1

0

esc_url() has a $_context argument which defaults to 'display'. It will replace & with & unless you change context to something else, e.g. sanitize_url uses 'db'. (Why it uses & instead of the usual & I don't understand, but it's deliberate.)

I'm guessing you're calling esc_url() somewhere in your code where you should be calling esc_url_raw() or sanitize_url() (which are identical) instead. These will not substitute &s.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.