Dashes instead of slashes as permalink structure separator

You can replace the dash with something else, preferably not a hyphen, because that would be hard to parse back. In the following example, I use a dot.

You have to change two parts: the outgoing permalinks (hook: "{$post_type}_link") and the request (hook: request) parsing for “incoming permalinks”.

The latter is harder, because it is very difficult to prevent collisions with other post types and taxonomies.

Here is a simple class with handlers for both cases. I have tested it with the post type page only and with permalink settings that put normal posts (post type post) at the root level.

class Undash_Permalinks
{
    /**
     * What to use instead of /
     *
     * @var string
     */
    private $replacement;

    /**
     * Undash_Permalinks constructor.
     *
     * @param string $replacement
     */
    public function __construct( $replacement )
    {
        $this->replacement = $replacement;
    }

    /**
     * Change the output URL
     *
     * @wp-hook page_link
     * @param   string $url
     *
     * @return string
     */
    public function output( $url )
    {
        $home     = home_url( "https://wordpress.stackexchange.com/" );
        $start    = strlen( $home );
        $sub      = substr( $url, $start );
        $replaced = str_replace( "https://wordpress.stackexchange.com/", $this->replacement, $sub );

        return $home . $replaced;
    }

    /**
     * Help WordPress to understand the requests as page requests
     *
     * @wp-hook request
     * @param   array $request
     *
     * @return array
     */
    public function input( array $request )
    {
        if ( empty ( $request[ 'name' ] ) )
            return $request;

        if ( FALSE === strpos( $request[ 'name' ], $this->replacement ) )
            return $request;

        $path = str_replace( $this->replacement, "https://wordpress.stackexchange.com/", $request[ 'name' ] );
        $page = get_page_by_path( $path );

        if ( ! $page )
            return $request;

        // Convince WP that we really have a page.
        $request[ 'pagename' ] = $path;
        unset( $request[ 'name' ] );

        return $request;
    }
}

Using this class is pretty simple:

add_action( 'after_setup_theme', function() {
    $undash = new Undash_Permalinks( '.' );
    add_filter( 'page_link', [ $undash, 'output' ] );
    add_filter( 'request', [ $undash, 'input' ] );
});

This might need some changes for other post types. For attachments you can either use the root directory as upload directory, or just live with the “folder”. Requests for them do not pass WordPress, so a filter would help at all.