wp_kses_attr

The timeline below displays how wordpress function wp_kses_attr has changed across different WordPress versions. If a version is not listed, refer to the next available version below.

WordPress Version: 6.3

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls `wp_kses_hair()` to split them further, and then
 * it builds up new HTML code from the data that `wp_kses_hair()` returns. It also
 * removes `<` and `>` characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * An array of allowed values can be defined for attributes. If the attribute value
 * doesn't fall into the list, the attribute will be removed from the tag.
 *
 * Attributes can be marked as required. If a required attribute is not present,
 * KSES will remove all attributes from the tag. As KSES doesn't match opening and
 * closing tags, it's not possible to safely remove the tag itself, the safest
 * fallback is to strip all attributes from the tag, instead.
 *
 * @since 1.0.0
 * @since 5.9.0 Added support for an array of allowed values for attributes.
 *              Added support for required attributes.
 *
 * @param string         $element           HTML element/tag.
 * @param string         $attr              HTML attributes from HTML element to closing HTML element tag.
 * @param array[]|string $allowed_html      An array of allowed HTML elements and attributes,
 *                                          or a context name such as 'post'. See wp_kses_allowed_html()
 *                                          for the list of accepted context names.
 * @param string[]       $allowed_protocols Array of allowed URL protocols.
 * @return string Sanitized HTML element.
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    // Is there a closing XHTML slash at the end of the attributes?
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    // Are any attributes allowed at all for this element?
    $element_low = strtolower($element);
    if (empty($allowed_html[$element_low]) || true === $allowed_html[$element_low]) {
        return "<{$element}{$xhtml_slash}>";
    }
    // Split it.
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    // Check if there are attributes that are required.
    $required_attrs = array_filter($allowed_html[$element_low], static function ($required_attr_limits) {
        return isset($required_attr_limits['required']) && true === $required_attr_limits['required'];
    });
    /*
     * If a required attribute check fails, we can return nothing for a self-closing tag,
     * but for a non-self-closing tag the best option is to return the element with attributes,
     * as KSES doesn't handle matching the relevant closing tag.
     */
    $stripped_tag = '';
    if (empty($xhtml_slash)) {
        $stripped_tag = "<{$element}>";
    }
    // Go through $attrarr, and save the allowed attributes for this element in $attr2.
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        // Check if this attribute is required.
        $required = isset($required_attrs[strtolower($arreach['name'])]);
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
            // If this was a required attribute, we can mark it as found.
            if ($required) {
                unset($required_attrs[strtolower($arreach['name'])]);
            }
        } elseif ($required) {
            // This attribute was required, but didn't pass the check. The entire tag is not allowed.
            return $stripped_tag;
        }
    }
    // If some required attributes weren't set, the entire tag is not allowed.
    if (!empty($required_attrs)) {
        return $stripped_tag;
    }
    // Remove any "<" or ">" characters.
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 6.1

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls `wp_kses_hair()` to split them further, and then
 * it builds up new HTML code from the data that `wp_kses_hair()` returns. It also
 * removes `<` and `>` characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * An array of allowed values can be defined for attributes. If the attribute value
 * doesn't fall into the list, the attribute will be removed from the tag.
 *
 * Attributes can be marked as required. If a required attribute is not present,
 * KSES will remove all attributes from the tag. As KSES doesn't match opening and
 * closing tags, it's not possible to safely remove the tag itself, the safest
 * fallback is to strip all attributes from the tag, instead.
 *
 * @since 1.0.0
 * @since 5.9.0 Added support for an array of allowed values for attributes.
 *              Added support for required attributes.
 *
 * @param string         $element           HTML element/tag.
 * @param string         $attr              HTML attributes from HTML element to closing HTML element tag.
 * @param array[]|string $allowed_html      An array of allowed HTML elements and attributes,
 *                                          or a context name such as 'post'. See wp_kses_allowed_html()
 *                                          for the list of accepted context names.
 * @param string[]       $allowed_protocols Array of allowed URL protocols.
 * @return string Sanitized HTML element.
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    // Is there a closing XHTML slash at the end of the attributes?
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    // Are any attributes allowed at all for this element?
    $element_low = strtolower($element);
    if (empty($allowed_html[$element_low]) || true === $allowed_html[$element_low]) {
        return "<{$element}{$xhtml_slash}>";
    }
    // Split it.
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    // Check if there are attributes that are required.
    $required_attrs = array_filter($allowed_html[$element_low], function ($required_attr_limits) {
        return isset($required_attr_limits['required']) && true === $required_attr_limits['required'];
    });
    /*
     * If a required attribute check fails, we can return nothing for a self-closing tag,
     * but for a non-self-closing tag the best option is to return the element with attributes,
     * as KSES doesn't handle matching the relevant closing tag.
     */
    $stripped_tag = '';
    if (empty($xhtml_slash)) {
        $stripped_tag = "<{$element}>";
    }
    // Go through $attrarr, and save the allowed attributes for this element in $attr2.
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        // Check if this attribute is required.
        $required = isset($required_attrs[strtolower($arreach['name'])]);
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
            // If this was a required attribute, we can mark it as found.
            if ($required) {
                unset($required_attrs[strtolower($arreach['name'])]);
            }
        } elseif ($required) {
            // This attribute was required, but didn't pass the check. The entire tag is not allowed.
            return $stripped_tag;
        }
    }
    // If some required attributes weren't set, the entire tag is not allowed.
    if (!empty($required_attrs)) {
        return $stripped_tag;
    }
    // Remove any "<" or ">" characters.
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 5.9

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls `wp_kses_hair()` to split them further, and then
 * it builds up new HTML code from the data that `kses_hair()` returns. It also
 * removes `<` and `>` characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * An array of allowed values can be defined for attributes. If the attribute value
 * doesn't fall into the list, the attribute will be removed from the tag.
 *
 * Attributes can be marked as required. If a required attribute is not present,
 * KSES will remove all attributes from the tag. As KSES doesn't match opening and
 * closing tags, it's not possible to safely remove the tag itself, the safest
 * fallback is to strip all attributes from the tag, instead.
 *
 * @since 1.0.0
 * @since 5.9.0 Added support for an array of allowed values for attributes.
 *              Added support for required attributes.
 *
 * @param string         $element           HTML element/tag.
 * @param string         $attr              HTML attributes from HTML element to closing HTML element tag.
 * @param array[]|string $allowed_html      An array of allowed HTML elements and attributes,
 *                                          or a context name such as 'post'. See wp_kses_allowed_html()
 *                                          for the list of accepted context names.
 * @param string[]       $allowed_protocols Array of allowed URL protocols.
 * @return string Sanitized HTML element.
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    // Is there a closing XHTML slash at the end of the attributes?
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    // Are any attributes allowed at all for this element?
    $element_low = strtolower($element);
    if (empty($allowed_html[$element_low]) || true === $allowed_html[$element_low]) {
        return "<{$element}{$xhtml_slash}>";
    }
    // Split it.
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    // Check if there are attributes that are required.
    $required_attrs = array_filter($allowed_html[$element_low], function ($required_attr_limits) {
        return isset($required_attr_limits['required']) && true === $required_attr_limits['required'];
    });
    /*
     * If a required attribute check fails, we can return nothing for a self-closing tag,
     * but for a non-self-closing tag the best option is to return the element with attributes,
     * as KSES doesn't handle matching the relevant closing tag.
     */
    $stripped_tag = '';
    if (empty($xhtml_slash)) {
        $stripped_tag = "<{$element}>";
    }
    // Go through $attrarr, and save the allowed attributes for this element in $attr2.
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        // Check if this attribute is required.
        $required = isset($required_attrs[strtolower($arreach['name'])]);
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
            // If this was a required attribute, we can mark it as found.
            if ($required) {
                unset($required_attrs[strtolower($arreach['name'])]);
            }
        } elseif ($required) {
            // This attribute was required, but didn't pass the check. The entire tag is not allowed.
            return $stripped_tag;
        }
    }
    // If some required attributes weren't set, the entire tag is not allowed.
    if (!empty($required_attrs)) {
        return $stripped_tag;
    }
    // Remove any "<" or ">" characters.
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 5.5

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls `wp_kses_hair()` to split them further, and then
 * it builds up new HTML code from the data that `kses_hair()` returns. It also
 * removes `<` and `>` characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string         $element           HTML element/tag.
 * @param string         $attr              HTML attributes from HTML element to closing HTML element tag.
 * @param array[]|string $allowed_html      An array of allowed HTML elements and attributes,
 *                                          or a context name such as 'post'. See wp_kses_allowed_html()
 *                                          for the list of accepted context names.
 * @param string[]       $allowed_protocols Array of allowed URL protocols.
 * @return string Sanitized HTML element.
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    // Is there a closing XHTML slash at the end of the attributes?
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    // Are any attributes allowed at all for this element?
    $element_low = strtolower($element);
    if (empty($allowed_html[$element_low]) || true === $allowed_html[$element_low]) {
        return "<{$element}{$xhtml_slash}>";
    }
    // Split it.
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    // Go through $attrarr, and save the allowed attributes for this element
    // in $attr2.
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    // Remove any "<" or ">" characters.
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 5.4

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls `wp_kses_hair()` to split them further, and then
 * it builds up new HTML code from the data that `kses_hair()` returns. It also
 * removes `<` and `>` characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string   $element           HTML element/tag.
 * @param string   $attr              HTML attributes from HTML element to closing HTML element tag.
 * @param array    $allowed_html      Allowed HTML elements.
 * @param string[] $allowed_protocols Array of allowed URL protocols.
 * @return string Sanitized HTML element.
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    // Is there a closing XHTML slash at the end of the attributes?
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    // Are any attributes allowed at all for this element?
    $element_low = strtolower($element);
    if (empty($allowed_html[$element_low]) || true === $allowed_html[$element_low]) {
        return "<{$element}{$xhtml_slash}>";
    }
    // Split it.
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    // Go through $attrarr, and save the allowed attributes for this element
    // in $attr2.
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    // Remove any "<" or ">" characters.
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 5.1

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls `wp_kses_hair()` to split them further, and then
 * it builds up new HTML code from the data that `kses_hair()` returns. It also
 * removes `<` and `>` characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string   $element           HTML element/tag.
 * @param string   $attr              HTML attributes from HTML element to closing HTML element tag.
 * @param array    $allowed_html      Allowed HTML elements.
 * @param string[] $allowed_protocols Array of allowed URL protocols.
 * @return string Sanitized HTML element.
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    // Is there a closing XHTML slash at the end of the attributes?
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    // Are any attributes allowed at all for this element?
    $element_low = strtolower($element);
    if (empty($allowed_html[$element_low]) || true === $allowed_html[$element_low]) {
        return "<{$element}{$xhtml_slash}>";
    }
    // Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    // Go through $attrarr, and save the allowed attributes for this element
    // in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    // Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 9.5

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element           HTML element/tag
 * @param string $attr              HTML attributes from HTML element to closing HTML element tag
 * @param array  $allowed_html      Allowed HTML elements
 * @param array  $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    // Is there a closing XHTML slash at the end of the attributes?
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    // Are any attributes allowed at all for this element?
    $element_low = strtolower($element);
    if (empty($allowed_html[$element_low]) || true === $allowed_html[$element_low]) {
        return "<{$element}{$xhtml_slash}>";
    }
    // Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    // Go through $attrarr, and save the allowed attributes for this element
    // in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    // Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 9.3

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element           HTML element/tag
 * @param string $attr              HTML attributes from HTML element to closing HTML element tag
 * @param array  $allowed_html      Allowed HTML elements
 * @param array  $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    // Is there a closing XHTML slash at the end of the attributes?
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    // Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || true === $allowed_html[strtolower($element)] || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    // Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    // Go through $attrarr, and save the allowed attributes for this element
    // in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    // Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: .20

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element           HTML element/tag
 * @param string $attr              HTML attributes from HTML element to closing HTML element tag
 * @param array  $allowed_html      Allowed HTML elements
 * @param array  $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    // Is there a closing XHTML slash at the end of the attributes?
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    // Are any attributes allowed at all for this element?
    $element_low = strtolower($element);
    if (empty($allowed_html[$element_low]) || true === $allowed_html[$element_low]) {
        return "<{$element}{$xhtml_slash}>";
    }
    // Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    // Go through $attrarr, and save the allowed attributes for this element
    // in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    // Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 9.2

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element           HTML element/tag
 * @param string $attr              HTML attributes from HTML element to closing HTML element tag
 * @param array  $allowed_html      Allowed HTML elements
 * @param array  $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    // Is there a closing XHTML slash at the end of the attributes?
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    // Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || true === $allowed_html[strtolower($element)] || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    // Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    // Go through $attrarr, and save the allowed attributes for this element
    // in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    // Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: .10

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element           HTML element/tag
 * @param string $attr              HTML attributes from HTML element to closing HTML element tag
 * @param array  $allowed_html      Allowed HTML elements
 * @param array  $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    // Is there a closing XHTML slash at the end of the attributes?
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    // Are any attributes allowed at all for this element?
    $element_low = strtolower($element);
    if (empty($allowed_html[$element_low]) || true === $allowed_html[$element_low]) {
        return "<{$element}{$xhtml_slash}>";
    }
    // Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    // Go through $attrarr, and save the allowed attributes for this element
    // in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    // Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 4.8

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element           HTML element/tag
 * @param string $attr              HTML attributes from HTML element to closing HTML element tag
 * @param array  $allowed_html      Allowed HTML elements
 * @param array  $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    // Is there a closing XHTML slash at the end of the attributes?
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    // Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || true === $allowed_html[strtolower($element)] || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    // Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    // Go through $attrarr, and save the allowed attributes for this element
    // in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    // Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 4.3

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element           HTML element/tag
 * @param string $attr              HTML attributes from HTML element to closing HTML element tag
 * @param array  $allowed_html      Allowed HTML elements
 * @param array  $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    // Is there a closing XHTML slash at the end of the attributes?
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    // Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    // Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    // Go through $attrarr, and save the allowed attributes for this element
    // in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    // Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: .20

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    // Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    // Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    // Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    // Go through $attrarr, and save the allowed attributes for this element
    // in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    // Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 2.2

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    // Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    // Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    // Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    // Go through $attrarr, and save the allowed attributes for this element
    // in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        // the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        // the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            // there are no checks
        } else {
            // there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            // it passed them
        }
        // if !is_array($current)
    }
    // foreach
    // Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: .10

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    // Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    // Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    // Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    // Go through $attrarr, and save the allowed attributes for this element
    // in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    // Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 4.2

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    // Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    // Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    // Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    // Go through $attrarr, and save the allowed attributes for this element
    // in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        // the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        // the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            // there are no checks
        } else {
            // there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            // it passed them
        }
        // if !is_array($current)
    }
    // foreach
    // Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 1.6

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 1.5

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        # the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        # the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            # there are no checks
        } else {
            # there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            # it passed them
        }
        # if !is_array($current)
    }
    # foreach
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: .40

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 1.4

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        # the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        # the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            # there are no checks
        } else {
            # there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            # it passed them
        }
        # if !is_array($current)
    }
    # foreach
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: .30

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 1.3

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        # the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        # the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            # there are no checks
        } else {
            # there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            # it passed them
        }
        # if !is_array($current)
    }
    # foreach
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: .20

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 1.2

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        # the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        # the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            # there are no checks
        } else {
            # there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            # it passed them
        }
        # if !is_array($current)
    }
    # foreach
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: .10

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 4.1

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        # the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        # the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            # there are no checks
        } else {
            # there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            # it passed them
        }
        # if !is_array($current)
    }
    # foreach
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 0.6

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 0.4

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        # the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        # the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            # there are no checks
        } else {
            # there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            # it passed them
        }
        # if !is_array($current)
    }
    # foreach
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: .30

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 0.3

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        # the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        # the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            # there are no checks
        } else {
            # there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            # it passed them
        }
        # if !is_array($current)
    }
    # foreach
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: .20

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 0.2

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        # the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        # the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            # there are no checks
        } else {
            # there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            # it passed them
        }
        # if !is_array($current)
    }
    # foreach
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: .10

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 4.0

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        # the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        # the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            # there are no checks
        } else {
            # there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            # it passed them
        }
        # if !is_array($current)
    }
    # foreach
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 9.7

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 9.2

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        # the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        # the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            # there are no checks
        } else {
            # there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            # it passed them
        }
        # if !is_array($current)
    }
    # foreach
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: .10

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 3.9

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        # the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        # the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            # there are no checks
        } else {
            # there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            # it passed them
        }
        # if !is_array($current)
    }
    # foreach
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 8.9

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 8.4

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        # the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        # the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            # there are no checks
        } else {
            # there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            # it passed them
        }
        # if !is_array($current)
    }
    # foreach
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: .30

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 8.3

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        # the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        # the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            # there are no checks
        } else {
            # there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            # it passed them
        }
        # if !is_array($current)
    }
    # foreach
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: .20

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 8.2

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        # the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        # the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            # there are no checks
        } else {
            # there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            # it passed them
        }
        # if !is_array($current)
    }
    # foreach
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: .10

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 3.8

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        # the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        # the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            # there are no checks
        } else {
            # there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            # it passed them
        }
        # if !is_array($current)
    }
    # foreach
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 7.9

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 7.5

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        # the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        # the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            # there are no checks
        } else {
            # there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            # it passed them
        }
        # if !is_array($current)
    }
    # foreach
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: .40

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 7.4

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        # the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        # the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            # there are no checks
        } else {
            # there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            # it passed them
        }
        # if !is_array($current)
    }
    # foreach
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: .30

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 7.3

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        # the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        # the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            # there are no checks
        } else {
            # there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            # it passed them
        }
        # if !is_array($current)
    }
    # foreach
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: .20

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 7.2

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        # the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        # the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            # there are no checks
        } else {
            # there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            # it passed them
        }
        # if !is_array($current)
    }
    # foreach
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: .10

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    foreach ($attrarr as $arreach) {
        if (wp_kses_attr_check($arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html)) {
            $attr2 .= ' ' . $arreach['whole'];
        }
    }
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}

WordPress Version: 3.7

/**
 * Removes all attributes, if none are allowed for this element.
 *
 * If some are allowed it calls wp_kses_hair() to split them further, and then
 * it builds up new HTML code from the data that kses_hair() returns. It also
 * removes "<" and ">" characters, if there are any left. One more thing it does
 * is to check if the tag has a closing XHTML slash, and if it does, it puts one
 * in the returned code as well.
 *
 * @since 1.0.0
 *
 * @param string $element HTML element/tag
 * @param string $attr HTML attributes from HTML element to closing HTML element tag
 * @param array $allowed_html Allowed HTML elements
 * @param array $allowed_protocols Allowed protocols to keep
 * @return string Sanitized HTML element
 */
function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols)
{
    # Is there a closing XHTML slash at the end of the attributes?
    if (!is_array($allowed_html)) {
        $allowed_html = wp_kses_allowed_html($allowed_html);
    }
    $xhtml_slash = '';
    if (preg_match('%\s*/\s*$%', $attr)) {
        $xhtml_slash = ' /';
    }
    # Are any attributes allowed at all for this element?
    if (!isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0) {
        return "<{$element}{$xhtml_slash}>";
    }
    # Split it
    $attrarr = wp_kses_hair($attr, $allowed_protocols);
    # Go through $attrarr, and save the allowed attributes for this element
    # in $attr2
    $attr2 = '';
    $allowed_attr = $allowed_html[strtolower($element)];
    foreach ($attrarr as $arreach) {
        if (!isset($allowed_attr[strtolower($arreach['name'])])) {
            continue;
        }
        # the attribute is not allowed
        $current = $allowed_attr[strtolower($arreach['name'])];
        if ($current == '') {
            continue;
        }
        # the attribute is not allowed
        if (strtolower($arreach['name']) == 'style') {
            $orig_value = $arreach['value'];
            $value = safecss_filter_attr($orig_value);
            if (empty($value)) {
                continue;
            }
            $arreach['value'] = $value;
            $arreach['whole'] = str_replace($orig_value, $value, $arreach['whole']);
        }
        if (!is_array($current)) {
            $attr2 .= ' ' . $arreach['whole'];
            # there are no checks
        } else {
            # there are some checks
            $ok = true;
            foreach ($current as $currkey => $currval) {
                if (!wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) {
                $attr2 .= ' ' . $arreach['whole'];
            }
            # it passed them
        }
        # if !is_array($current)
    }
    # foreach
    # Remove any "<" or ">" characters
    $attr2 = preg_replace('/[<>]/', '', $attr2);
    return "<{$element}{$attr2}{$xhtml_slash}>";
}