1

为了构建查询,有没有办法在 Wordpress 中解析 URL。例如,如果我想在侧边栏中有一个wp_get_archives()通过 AJAX 处理的档案列表(使用 显示),我如何让 Wordpress 构建 URL 并返回 JSON 数据。显然我可以自己解析一个 url 并找出默认查询,但如果我可以使用与 Wordpress 相同的方法,那就太好了。我查看了 $wp_query 对象,但不确定如何重用代码。

//jQuery:
$('#archives a').on('click', function(evt) {

     $.ajax({
        ....
        data: { url: '...' }
        success: function(result) {
            //parse JSON and append to HTML
        }
        ....
     });

});

//PHP:
function process_ajax() {


    //parse url
    //figure query
    //return JSON

}

感谢您的任何意见。

4

3 回答 3

1

我扩展了 WP 类并覆盖了 parse_request() 方法以允许解析预定义的 URL。函数中的大部分逻辑都是完全相同的,这有点多余,但除非有人知道另一种方法,否则这是我想出的最好的方法。效果很好。

class AJAX_WP extends WP {

    /*
     *  Overwrite the parse_request function to allow for
     *  processing of urls defined in variables
    */

    function parse_request( $url ) {
        global $wp_rewrite;

        //validate url
        if(empty($url))
            return false;

        //sanitize
        $url = filter_var($url, FILTER_SANITIZE_URL);

        $this->query_vars = array();
        $post_type_query_vars = array();

        if ( is_array($extra_query_vars) )
            $this->extra_query_vars = & $extra_query_vars;
        else if (! empty($extra_query_vars))
            parse_str($extra_query_vars, $this->extra_query_vars);

        // Process PATH_INFO, REQUEST_URI, and 404 for permalinks.

        // Fetch the rewrite rules.
        $rewrite = $wp_rewrite->wp_rewrite_rules();

        if ( ! empty($rewrite) ) {
            // If we match a rewrite rule, this will be cleared.
            $error = '404';
            $this->did_permalink = true;

            //parse url
            $_url = parse_url($url);

            //set path info
            $pathinfo = $_url['path'];
            $pathinfo_array = explode('?', $pathinfo);
            $pathinfo = str_replace("%", "%25", $pathinfo_array[0]);

            //req_uri
            $req_uri = $_url['path'];
            $req_uri_array = explode('?', $req_uri);
            $req_uri = $req_uri_array[0];

            //self
            $self = $_url['path'];
            $home_path = parse_url(home_url());
            if ( isset($home_path['path']) )
                $home_path = $home_path['path'];
            else
                $home_path = '';
            $home_path = trim($home_path, '/');

            // Trim path info from the end and the leading home path from the
            // front.  For path info requests, this leaves us with the requesting
            // filename, if any.  For 404 requests, this leaves us with the
            // requested permalink.
            $req_uri = str_replace($pathinfo, '', $req_uri);
            $req_uri = trim($req_uri, '/');
            $req_uri = preg_replace("|^$home_path|", '', $req_uri);
            $req_uri = trim($req_uri, '/');
            $pathinfo = trim($pathinfo, '/');
            $pathinfo = preg_replace("|^$home_path|", '', $pathinfo);
            $pathinfo = trim($pathinfo, '/');
            $self = trim($self, '/');
            $self = preg_replace("|^$home_path|", '', $self);
            $self = trim($self, '/');

            // The requested permalink is in $pathinfo for path info requests and
            //  $req_uri for other requests.
            if ( ! empty($pathinfo) && !preg_match('|^.*' . $wp_rewrite->index . '$|', $pathinfo) ) {
                $request = $pathinfo;
            } else {
                // If the request uri is the index, blank it out so that we don't try to match it against a rule.
                if ( $req_uri == $wp_rewrite->index )
                    $req_uri = '';
                $request = $req_uri;
            }

            $this->request = $request;

            // Look for matches.
            $request_match = $request;
            if ( empty( $request_match ) ) {
                // An empty request could only match against ^$ regex
                if ( isset( $rewrite['$'] ) ) {
                    $this->matched_rule = '$';
                    $query = $rewrite['$'];
                    $matches = array('');
                }
            } else if ( $req_uri != 'wp-app.php' ) {
                foreach ( (array) $rewrite as $match => $query ) {
                    // If the requesting file is the anchor of the match, prepend it to the path info.
                    if ( ! empty($req_uri) && strpos($match, $req_uri) === 0 && $req_uri != $request )
                        $request_match = $req_uri . '/' . $request;

                    if ( preg_match("#^$match#", $request_match, $matches) ||
                        preg_match("#^$match#", urldecode($request_match), $matches) ) {

                        if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
                            // this is a verbose page match, lets check to be sure about it
                            if ( ! get_page_by_path( $matches[ $varmatch[1] ] ) )
                                continue;
                        }

                        // Got a match.
                        $this->matched_rule = $match;
                        break;
                    }
                }
            }

            if ( isset( $this->matched_rule ) ) {
                // Trim the query of everything up to the '?'.
                $query = preg_replace("!^.+\?!", '', $query);

                // Substitute the substring matches into the query.
                $query = addslashes(WP_MatchesMapRegex::apply($query, $matches));

                $this->matched_query = $query;

                // Parse the query.
                parse_str($query, $perma_query_vars);

                // If we're processing a 404 request, clear the error var
                // since we found something.
                unset( $_GET['error'] );
                unset( $error );
            }

            // If req_uri is empty or if it is a request for ourself, unset error.
            if ( empty($request) || $req_uri == $self || strpos($_url['path'], 'wp-admin/') !== false ) {
                unset( $_GET['error'] );
                unset( $error );

                if ( isset($perma_query_vars) && strpos($_url['path'], 'wp-admin/') !== false )
                    unset( $perma_query_vars );

                $this->did_permalink = false;
            }
        }

        $this->public_query_vars = apply_filters('query_vars', $this->public_query_vars);

        foreach ( $GLOBALS['wp_post_types'] as $post_type => $t )
            if ( $t->query_var )
                $post_type_query_vars[$t->query_var] = $post_type;

        foreach ( $this->public_query_vars as $wpvar ) {
            if ( isset( $this->extra_query_vars[$wpvar] ) )
                $this->query_vars[$wpvar] = $this->extra_query_vars[$wpvar];
            elseif ( isset( $_POST[$wpvar] ) )
                $this->query_vars[$wpvar] = $_POST[$wpvar];
            elseif ( isset( $_GET[$wpvar] ) )
                $this->query_vars[$wpvar] = $_GET[$wpvar];
            elseif ( isset( $perma_query_vars[$wpvar] ) )
                $this->query_vars[$wpvar] = $perma_query_vars[$wpvar];

            if ( !empty( $this->query_vars[$wpvar] ) ) {
                if ( ! is_array( $this->query_vars[$wpvar] ) ) {
                    $this->query_vars[$wpvar] = (string) $this->query_vars[$wpvar];
                } else {
                    foreach ( $this->query_vars[$wpvar] as $vkey => $v ) {
                        if ( !is_object( $v ) ) {
                            $this->query_vars[$wpvar][$vkey] = (string) $v;
                        }
                    }
                }

                if ( isset($post_type_query_vars[$wpvar] ) ) {
                    $this->query_vars['post_type'] = $post_type_query_vars[$wpvar];
                    $this->query_vars['name'] = $this->query_vars[$wpvar];
                }
            }
        }

        // Convert urldecoded spaces back into +
        foreach ( $GLOBALS['wp_taxonomies'] as $taxonomy => $t )
            if ( $t->query_var && isset( $this->query_vars[$t->query_var] ) )
                $this->query_vars[$t->query_var] = str_replace( ' ', '+', $this->query_vars[$t->query_var] );

        // Limit publicly queried post_types to those that are publicly_queryable
        if ( isset( $this->query_vars['post_type']) ) {
            $queryable_post_types = get_post_types( array('publicly_queryable' => true) );
            if ( ! is_array( $this->query_vars['post_type'] ) ) {
                if ( ! in_array( $this->query_vars['post_type'], $queryable_post_types ) )
                    unset( $this->query_vars['post_type'] );
            } else {
                $this->query_vars['post_type'] = array_intersect( $this->query_vars['post_type'], $queryable_post_types );
            }
        }

        foreach ( (array) $this->private_query_vars as $var) {
            if ( isset($this->extra_query_vars[$var]) )
                $this->query_vars[$var] = $this->extra_query_vars[$var];
        }

        if ( isset($error) )
            $this->query_vars['error'] = $error;

        $this->query_vars = apply_filters('request', $this->query_vars);

        do_action_ref_array('parse_request', array(&$this));

    }

}
于 2012-05-24T16:07:50.930 回答
0

这是我用来在 WordPress 4.2.2 上使用的最终代码,非常感谢 Chris:

/**
 * An extension of the global WP object class for URL parsing / query_var generating ability over AJAX
 *
 * Essentially, it lets you specify a url.
 *
 * Example of use:
 *
 *  global $wp;
 *  $wp = new AJAX_WP();
 *  $wp->main( $url );
 *
 * @since 2015-June-2
 */
class AJAX_WP extends WP {

    /**
     * Parse request to find correct WordPress query.
     *
     * Sets up the query variables based on the request. There are also many
     * filters and actions that can be used to further manipulate the result.
     *
     * @since 2.0.0
     *
     * @param array|string $extra_query_vars Set the extra query variables.
     */
    public function parse_request( $url ) {

        global $wp_rewrite;

        //validate url
        if(empty($url))
            return false;

        //sanitize
        $url = filter_var($url, FILTER_SANITIZE_URL);

        /**
         * Filter whether to parse the request.
         *
         * @since 3.5.0
         *
         * @param bool         $bool             Whether or not to parse the request. Default true.
         * @param WP           $this             Current WordPress environment instance.
         * @param array|string $extra_query_vars Extra passed query variables.
         */
        if ( ! apply_filters( 'do_parse_request', true, $this, $extra_query_vars ) )
            return;

        $this->query_vars = array();
        $post_type_query_vars = array();

        if ( is_array( $extra_query_vars ) ) {
            $this->extra_query_vars = & $extra_query_vars;
        } elseif ( ! empty( $extra_query_vars ) ) {
            parse_str( $extra_query_vars, $this->extra_query_vars );
        }
        // Process PATH_INFO, REQUEST_URI, and 404 for permalinks.

        // Fetch the rewrite rules.
        $rewrite = $wp_rewrite->wp_rewrite_rules();

        if ( ! empty($rewrite) ) {
            // If we match a rewrite rule, this will be cleared.
            $error = '404';
            $this->did_permalink = true;

            /*$pathinfo = isset( $_SERVER['PATH_INFO'] ) ? $_SERVER['PATH_INFO'] : '';
            list( $pathinfo ) = explode( '?', $pathinfo );
            $pathinfo = str_replace( "%", "%25", $pathinfo );

            list( $req_uri ) = explode( '?', $_SERVER['REQUEST_URI'] );
            $self = $_SERVER['PHP_SELF'];
            $home_path = trim( parse_url( home_url(), PHP_URL_PATH ), '/' );*/

            //parse url
            $_url = parse_url($url);

            //set path info
            $pathinfo = $_url['path'];
            $pathinfo_array = explode('?', $pathinfo);
            $pathinfo = str_replace("%", "%25", $pathinfo_array[0]);

            //req_uri
            $req_uri = $_url['path'];
            $req_uri_array = explode('?', $req_uri);
            $req_uri = $req_uri_array[0];

            //self
            $self = $_url['path'];
            $home_path = parse_url(home_url());
            if ( isset($home_path['path']) )
                $home_path = $home_path['path'];
            else
                $home_path = '';
            $home_path = trim($home_path, '/');


            // Trim path info from the end and the leading home path from the
            // front. For path info requests, this leaves us with the requesting
            // filename, if any. For 404 requests, this leaves us with the
            // requested permalink.
            $req_uri = str_replace($pathinfo, '', $req_uri);
            $req_uri = trim($req_uri, '/');
            $req_uri = preg_replace("|^$home_path|i", '', $req_uri);
            $req_uri = trim($req_uri, '/');
            $pathinfo = trim($pathinfo, '/');
            $pathinfo = preg_replace("|^$home_path|i", '', $pathinfo);
            $pathinfo = trim($pathinfo, '/');
            $self = trim($self, '/');
            $self = preg_replace("|^$home_path|i", '', $self);
            $self = trim($self, '/');

            // The requested permalink is in $pathinfo for path info requests and
            //  $req_uri for other requests.
            if ( ! empty($pathinfo) && !preg_match('|^.*' . $wp_rewrite->index . '$|', $pathinfo) ) {
                $request = $pathinfo;
            } else {
                // If the request uri is the index, blank it out so that we don't try to match it against a rule.
                if ( $req_uri == $wp_rewrite->index )
                    $req_uri = '';
                $request = $req_uri;
            }

            $this->request = $request;

            // Look for matches.
            $request_match = $request;
            if ( empty( $request_match ) ) {
                // An empty request could only match against ^$ regex
                if ( isset( $rewrite['$'] ) ) {
                    $this->matched_rule = '$';
                    $query = $rewrite['$'];
                    $matches = array('');
                }
            } else {
                foreach ( (array) $rewrite as $match => $query ) {
                    // If the requesting file is the anchor of the match, prepend it to the path info.
                    if ( ! empty($req_uri) && strpos($match, $req_uri) === 0 && $req_uri != $request )
                        $request_match = $req_uri . '/' . $request;

                    if ( preg_match("#^$match#", $request_match, $matches) ||
                        preg_match("#^$match#", urldecode($request_match), $matches) ) {

                        if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
                            // This is a verbose page match, let's check to be sure about it.
                            if ( ! get_page_by_path( $matches[ $varmatch[1] ] ) )
                                continue;
                        }

                        // Got a match.
                        $this->matched_rule = $match;
                        break;
                    }
                }
            }

            if ( isset( $this->matched_rule ) ) {
                // Trim the query of everything up to the '?'.
                $query = preg_replace("!^.+\?!", '', $query);

                // Substitute the substring matches into the query.
                $query = addslashes(WP_MatchesMapRegex::apply($query, $matches));

                $this->matched_query = $query;

                // Parse the query.
                parse_str($query, $perma_query_vars);

                // If we're processing a 404 request, clear the error var since we found something.
                if ( '404' == $error )
                    unset( $error, $_GET['error'] );
            }

            // If req_uri is empty or if it is a request for ourself, unset error.
            if ( empty($request) || $req_uri == $self ) {
                unset( $error, $_GET['error'] );

                /*
                Not doing this — it's AJAX and will always be true

                if ( isset($perma_query_vars) && strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) {
                    unset( $perma_query_vars );
                }*/

                $this->did_permalink = false;
            }
        }

        /**
         * Filter the query variables whitelist before processing.
         *
         * Allows (publicly allowed) query vars to be added, removed, or changed prior
         * to executing the query. Needed to allow custom rewrite rules using your own arguments
         * to work, or any other custom query variables you want to be publicly available.
         *
         * @since 1.5.0
         *
         * @param array $public_query_vars The array of whitelisted query variables.
         */
        $this->public_query_vars = apply_filters( 'query_vars', $this->public_query_vars );

        foreach ( get_post_types( array(), 'objects' ) as $post_type => $t )
            if ( $t->query_var )
                $post_type_query_vars[$t->query_var] = $post_type;

        foreach ( $this->public_query_vars as $wpvar ) {
            if ( isset( $this->extra_query_vars[$wpvar] ) )
                $this->query_vars[$wpvar] = $this->extra_query_vars[$wpvar];
            elseif ( isset( $_POST[$wpvar] ) )
                $this->query_vars[$wpvar] = $_POST[$wpvar];
            elseif ( isset( $_GET[$wpvar] ) )
                $this->query_vars[$wpvar] = $_GET[$wpvar];
            elseif ( isset( $perma_query_vars[$wpvar] ) ) {
                $this->query_vars[$wpvar] = $perma_query_vars[$wpvar];
                }

            if ( !empty( $this->query_vars[$wpvar] ) ) {
                if ( ! is_array( $this->query_vars[$wpvar] ) ) {
                    $this->query_vars[$wpvar] = (string) $this->query_vars[$wpvar];
                } else {
                    foreach ( $this->query_vars[$wpvar] as $vkey => $v ) {
                        if ( !is_object( $v ) ) {
                            $this->query_vars[$wpvar][$vkey] = (string) $v;
                        }
                    }
                }

                if ( isset($post_type_query_vars[$wpvar] ) ) {
                    $this->query_vars['post_type'] = $post_type_query_vars[$wpvar];
                    $this->query_vars['name'] = $this->query_vars[$wpvar];
                }
            }
        }

        // Convert urldecoded spaces back into +
        foreach ( get_taxonomies( array() , 'objects' ) as $taxonomy => $t )
            if ( $t->query_var && isset( $this->query_vars[$t->query_var] ) )
                $this->query_vars[$t->query_var] = str_replace( ' ', '+', $this->query_vars[$t->query_var] );

        // Limit publicly queried post_types to those that are publicly_queryable
        if ( isset( $this->query_vars['post_type']) ) {
            $queryable_post_types = get_post_types( array('publicly_queryable' => true) );
            if ( ! is_array( $this->query_vars['post_type'] ) ) {
                if ( ! in_array( $this->query_vars['post_type'], $queryable_post_types ) )
                    unset( $this->query_vars['post_type'] );
            } else {
                $this->query_vars['post_type'] = array_intersect( $this->query_vars['post_type'], $queryable_post_types );
            }
        }

        foreach ( (array) $this->private_query_vars as $var) {
            if ( isset($this->extra_query_vars[$var]) )
                $this->query_vars[$var] = $this->extra_query_vars[$var];
        }

        if ( isset($error) )
            $this->query_vars['error'] = $error;

        /**
         * Filter the array of parsed query variables.
         *
         * @since 2.1.0
         *
         * @param array $query_vars The array of requested query variables.
         */
        $this->query_vars = apply_filters( 'request', $this->query_vars );


        /**
         * Fires once all query variables for the current request have been parsed.
         *
         * @since 2.1.0
         *
         * @param WP &$this Current WordPress environment instance (passed by reference).
         */
        do_action_ref_array( 'parse_request', array( &$this ) );

    }

    /**
     * Sets up all of the variables required by the WordPress environment.
     *
     * The action 'wp' has one parameter that references the WP object. It
     * allows for accessing the properties and methods to further manipulate the
     * object.
     *
     * @since 2.0.0
     *
     * @param string|array $query_args Passed to {@link parse_request()}
     */
    public function main( $url ) {

        $this->init();
        $this->parse_request( $url );
        $this->send_headers();
        $this->query_posts();
        $this->handle_404();
        $this->register_globals();

        /**
         * Fires once the WordPress environment has been set up.
         *
         * @since 2.1.0
         *
         * @param WP &$this Current WordPress environment instance (passed by reference).
         */
        do_action_ref_array( 'wp', array( &$this ) );
    }

}

此外,我必须添加此过滤器以使其全部正常工作:

/**
 * Make sure that all the post types are available as query variables
 *
 * This fixes a problem with AJAX_WP not returning custom post types.
 *
 * @since 2015-June-2
 * @param array $public_vars
 * @return array
 */
function ananda_ajax_public_query_post_types( $public_vars ) {

        return array_merge( get_post_types( array('publicly_queryable' => true) ), $public_vars );
}

这是添加的实际过滤器:

add_filter( 'query_vars', 'ananda_ajax_public_query_post_types', 10, 1 );
于 2015-06-02T23:22:21.063 回答
0

我知道这是旧的,但你们真的帮助了我,所以我想我会向前支付。这是一个更简单的版本(我也希望它更安全一些):

class PermalinkParser extends WP{


        function parse_permalink($url) {
            $path                 = parse_url($url, PHP_URL_PATH);
            $previous             = $_SERVER;
            $_SERVER['PATH_INFO'] = $_SERVER['REQUEST_URI'] = $path;
            $_SERVER['PHP_SELF']  = str_replace($_SERVER['DOCUMENT_ROOT'],'',  ABSPATH . 'index.php');

            $this->parse_request();
            $_SERVER = $previous;
            return $this->query_vars;
        }

        function main( $query_args = '' ) {
            // do not run this
        }
    }
于 2019-08-09T10:51:23.413 回答