uncatcrea / wp-appkit

WP-AppKit WordPress plugin (create mobile apps connected to WordPress)
http://uncategorized-creations.com/
194 stars 66 forks source link

Internal links #358

Closed bjdeng closed 6 years ago

bjdeng commented 6 years ago

I'm trying to figure out app routing so that internal links in site pages will keep users in the app.

For example, if a post at website.com/post contains a link in the body to website.com/anotherPost, it currently takes me to the live version of that page, but when in the app it should take me to the app version. Is there a way to do this?

I'm on the development-pwa branch

mleroi commented 6 years ago

Hi @bjdeng ! Here is a snippet that allows to replace website's posts and pages urls by corresponding app routes in all posts content sent to the app. This way, posts links that are inside posts content will open in the app. This code can be put in a php file (for example internal-links.php) in the php folder of your WP-AppKit theme:

add_filter('wpak_post_content_format','wpak_handle_internal_links',10,2);
function wpak_handle_internal_links( $content, $post ) {

    //Find all internal urls:
    preg_match_all( '#(["\'])'. get_option('siteurl') .'/([^"\']+)#', $content, $internal_urls  );

    if ( !empty( $internal_urls ) ) {

        //For each internal url, find the matching wp entity (post, page etc).
        foreach( $internal_urls[2] as $key => $internal_url ) {

            $wp_query = wpak_get_wp_query_from_url( $internal_url );

            if ( $wp_query ) {
                //If the url correspond to a post or a page, replace the url by the corresponding internal app route:
                if ( $wp_query->is_single() ) {
                    $content = str_replace( $internal_urls[0][$key], $internal_urls[1][$key] .'#single/posts/'. $wp_query->post->ID .'/', $content );
                } else if ( $wp_query->is_page() ) {
                    $content = str_replace( $internal_urls[0][$key], $internal_urls[1][$key] .'#page/'. $wp_query->post->ID .'/', $content );
                }
            }

        }

    }

    return $content;
}

/**
 * Url parsing logic inspired from WP::parse_request() (wp-includes/class-wp.php)
 */
function wpak_get_wp_query_from_url( $url ) {
    global $wp_rewrite;

    $wp_query = null;

    $rewrite = $wp_rewrite->wp_rewrite_rules();

    $match_found = false;
    foreach ( (array) $rewrite as $match => $query ) {
        if ( preg_match("#^$match#", $url, $matches) ) {
            $query = preg_replace("!^.+\?!", '', $query);

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

            $wp_query = new WP_Query( $query );
            break;
        }
    }

    return $wp_query;
}

Tell me if this works for you. If so we'll certainly set something like it by default in core's PWA export.

mleroi commented 6 years ago

Implemented in https://github.com/uncatcrea/wp-appkit/commit/01124ac03c1fcad8e0e080fd23502f83f48f7f09