initial_static_options = array ( 'has_pro_version' =>0, 'show_opts' =>true, 'show_rating_message'=>true, 'display_tabs' =>false, 'required_role' =>'install_plugins', 'default_managed' =>'singlesite', //network, singlesite, both ); $this->initial_user_options = array ( 'hierarchy_permalinks_too' => 1, 'custom_post_types' => "post,", 'hierarchy_using' => "query_post", // "query_post" or "modify_post_obj" or "rewrite" (worst case) ); } public function __construct_my() { add_action( 'registered_post_type', [$this, 'enable_hierarchy_fields'], 123, 2); add_filter( 'post_type_labels_'.$post_type='post', [$this, 'enable_hierarchy_fields_for_js'], 11, 2); if($this->opts['hierarchy_permalinks_too']) { //just example funcs into init if(is_admin()) add_action('init', array($this, 'init_action'), 777 ); // change permalinks on front-end source links add_filter('pre_post_link', array($this,'change_permalinks'), 8, 3 ); // DIFFICULT PART: making WP to recoginzed the hierarchied URL-STRUCTURE // // (modify_post_obj): using "registered_post_type" // ** "register_post_type_args" almost same as "registered_post_type", but worse (the labels are set as "page" (see output: https://pastebin.com/raw/iVahbbLw ). also, 'rewrite' gives error. (See more details at: https://pastebin.com/raw/0ujkRzLE ) . Also, similar results to "reregister_post" so, i use only this version ( `reregister_post` is worse than `modify_post_obj`. see: https://pastebin.com/raw/9ZabSn0E ) if($this->opts['hierarchy_using'] == 'modify_post_obj'){ add_action('registered_post_type', array($this, 'method__modify_post_obj'), 150 , 2); } // (query_post): using "pre_get_posts" elseif($this->opts['hierarchy_using'] == 'query_post'){ add_filter( 'pre_get_posts', array($this,'method__query') , 888 ); add_action( 'registered_post_type', array($this, 'hierarchy_for_custom_post'), 90 , 2 ); // $this->load_pro(); } //(rewrite): using "add_rewrite_rule" elseif($this->opts['hierarchy_using'] == 'rewrite'){ add_action('init', array($this, 'method__rewrite'), 150 ); } //check if permalinks not enabled add_action('current_screen', function(){ $screen = get_current_screen(); if ( $screen->base == 'post' ) { $this->alert_if_not_pretty_permalinks(); } } ); } } // ============================================================================================================== // // ============================================================================================================== // public function deactivation_funcs($network_wide){ if ( is_multisite() ) { // && $network_wide global $wpdb; $blogs = $wpdb->get_col("SELECT blog_id FROM ". $wpdb->blogs); foreach ($blogs as $blog_id) { switch_to_blog($blog_id); $this->flush_rules_original(); restore_current_blog(); } } else { $this->flush_rules_original(); } //in activtion could have been: $this->add_rewrites(); } public function flush_rules_original() { //$this->update_option_CHOSEN('rewrite_rules', $this->get_option_CHOSEN('rewrite_rules_BACKUPED__AHPTP') ); $this->flush_rules(false); } // ============================================================================================================== // // ============================================================================================================== // // register_post_type_args //$args['rewrite']['slug']='/'; public function init_action() { $this->flush_rules_if_needed(__FILE__); } // note, with 'registered_post_type' argument $post_type_object is same as $GLOBALS['wp_post_types']['post'], but globalized one (from: wp-includes/post: 1120 ), however, they behave samely // ===================================================================== // ============== Add PARENT FIELD to POST TYPE support =========== public function enable_hierarchy_fields($post_type, $post_type_object){ if($post_type== 'post' ){ $post_type_object->hierarchical = true; $GLOBALS['_wp_post_type_features']['post']['page-attributes']=true; } } public function enable_hierarchy_fields_for_js($labels){ $labels->parent_item_colon='Parent Post'; return $labels; } // ===================================================================== // =================================================== // ============== Start URL hierarchy =========== // method 1 (seems useless): child posts work, pages (or other things) go to 404 public function method__modify_post_obj($post_type, $post_type_object){ $Type = 'post'; if($post_type==$Type){ $post_type_object->rewrite = array('with_front'=>false, 'slug'=>'/', 'feeds' => 1); // otherwise bugs in class-wp-post-type.php 566 ; [pages] => 1 [feeds] => 1 [ep_mask] => 1 $post_type_object->query_var = 'post'; //'post' or true; without this line, everything goes 404 // at this moment, we cant call that function, so, call later add_action('init', function(){ // this function causes exactly to finalize everything before. so, it makes hierarchied post to work, but break other post types (page or etc..) to 404 $GLOBALS['wp_post_types']['post']-> add_rewrite_rules(); // ref: https://pastebin.com/raw/3yVg8jXp // $this->add_rewrite_for_post(); } ); } } // method 2 (also, independent) public function method__query( $query ) { $pType = 'post'; $q=$query; if( $q->is_main_query() && !is_admin() ) { //at first, check if it's attachment, because only attachment meet this rewrite like hierarchied post if( true // needs to be attachement: wp-includes\class-wp-query.php, but everything happens in parse_request(), because of rewrite match, that is attachement //&& ( (!is_multisite() && $q->is_attachment) || (is_multisite() && !$q->is_attachment) ) ) ){ $possible_post_path = trailingslashit( preg_replace_callback('/(.*?)\/((page|feed|rdf|rss|rss2|atom)\/.*)/i', function($matches) { return $matches[1]; } , $this->path_after_blog() ) ); //if seems hierarchied - 2 slashes at least, like: parent/child/ if(substr_count($possible_post_path, "/") >= 2) { $post=get_page_by_path($possible_post_path, OBJECT, $pType); if ($post){ // create query //no need of $q->init(); $q->parse_query( array('post_type'=>array($pType) ) ) ; //better than $q->set('post_type', 'post'); $q->is_home = false; //$q->is_page = $method_is_page ? true : false; $q->is_single = true; $q->is_singular = true; $q->queried_object_id=$post->ID; $q->set('page_id',$post->ID); //add_action('wp', function (){ v($GLOBALS['wp_query']); }); return $q; } } } } return $q; } public function hierarchy_for_custom_post($post_type, $post_type_object){ $custom_posts = !empty( $this->opts["custom_post_types"] ) ? array_filter( explode(",", $this->opts["custom_post_types"] ) ) : array( 'post'); foreach ($custom_posts as $each_type){ $each_type = trim($each_type); if($post_type==$each_type){ $post_type_object->hierarchical = true; } } } /* // method 2: hierarchy posts work, pages break // public function method__reregister_post() { // $Type = 'post'; // $post_obj = get_post_type_object($Type); // $args_existing = json_decode(json_encode($post_obj), true); // $args_new = $args_existing; // $args_new['has_archive'] = true; // // $args_new['query_var'] = 'post'; // 'post' or true // $args_new['rewrite'] = array('with_front'=>false, 'slug'=>'/'); // / 'rewrite' => array("ep_mask"=>EP_PERMALINK ...) OR 'permalink_epmask'=>EP_PERMALINK, // // register_post_type( $Type, $args_new ); // register_post_type function : https://pastebin.com/raw/3fjqYHPj // $this->add_rewrite_for_post(); // } public function method__rewrite(){ add_rewrite_rule( $reg = '([^/]*)/(.*)' , $match='index.php?name=$matches[2]', $priority='top' ); $this->flush_rules_if_needed(__FILE__); // https://pastebin.com/raw/kvEXCqKQ // //add_rewrite_rule($reg, 'index.php?name=$matches[2]', 'top' ); // '([^/]+)/?', //([^/]+) //([^/]*)/(.*) // add_rewrite_rule( '([^/]*)/(.*)', 'index.php?name=$matches[2]', 'top' ); //$rules = get_option( 'rewrite_rules' ); // if(!is_admin()) { var_dump($rules ); } // check if our rules are not yet included if ( false ){ if (! isset( $rules[$reg] ) ) { // $this->update_option_CHOSEN('rewrite_rules_BACKUPED__AHPTP', $rules ); // https://developer.wordpress.org/reference/functions/add_rewrite_tag/ add_rewrite_rule($reg, 'index.php?name=$matches[2]', 'top' ); // //add_rewrite_rule('^\/(.*)(\/|?|#|)$', 'index.php?pagename=$matches[1]', 'top'); //add_rewrite_tag( '%postname%', '(.?.+?)', 'pagename=$matches[1]' ); flush_rewrite_rules(); } } //these re defaults for new type // './?$' => string 'index.php?post_type=post' (length=24) // './feed/(feed|rdf|rss|rss2|atom)/?$' => string 'index.php?post_type=post&feed=$matches[1]' (length=41) // './(feed|rdf|rss|rss2|atom)/?$' => string 'index.php?post_type=post&feed=$matches[1]' (length=41) // './page/([0-9]{1,})/?$' => string 'index.php?post_type=post&paged=$matches[1]' (length=42) } public function add_rewrite_for_post(){ add_rewrite_rule( $reg = '.+/([^/]+)/?$' , $match='index.php?name=$matches[1]', $priority='top' ); } */ // ==================== POST_LINK (WHEN %postname% tags not available yet {after 10'th priority it's available} ) ======================// //i.e: http://example.com/post_name OR http://example.com/%if_any_additinonal_custom_structural_tag%/post_name public function change_permalinks( $permalink, $post=false, $leavename=false ) { $postTypes = !empty($this->opts["custom_post_types"]) ? array_filter(explode(",", $this->opts["custom_post_types"] )) : array('post'); foreach ($postTypes as $each_post_type){ if($post->post_type == $each_post_type){ // return if %postname% tag is not present in the url: if ( false === strpos( $permalink, '%postname%')) { return $permalink; } $permalink = $this->remove_extra_slashes('/'. $this->get_parent_slugs($post). '/'. '%postname%' ); } } return $permalink; } public function get_parent_slugs($post){ $final_SLUGG = ''; if (!empty($post->post_parent)){ $parent_post= get_post($post->post_parent); while(!empty($parent_post)){ $final_SLUGG = $parent_post->post_name .'/'.$final_SLUGG; if (!empty($parent_post->post_parent) ) { $parent_post = get_post( $parent_post->post_parent); } else{ break ;} } } return $final_SLUGG; } // =========================================================================================================================================== // public function alert_if_not_pretty_permalinks() { if( $this->opts['hierarchy_permalinks_too'] && !get_option('permalink_structure') ){ echo ''; } } // =================================== Options page ================================ // public function opts_page_output() { $this->settings_page_part("start"); ?> active_tab=="Options") { //if form updated if(isset($_POST["_wpnonce"]) && check_admin_referer("nonce_".$this->plugin_slug) ) { $this->opts['hierarchy_permalinks_too'] = !empty($_POST[ $this->plugin_slug ]['hierarchy_permalinks_too']) ; $this->opts['hierarchy_using'] = sanitize_key($_POST[ $this->plugin_slug ]['hierarchy_using']) ; $this->opts['custom_post_types'] = trim(sanitize_text_field($_POST[ $this->plugin_slug ]['custom_post_types'])) ; $this->opts['last_update_time'] = time() ; // need only for flush rules $this->update_opts(); $this->flush_rules_checkmark(true); } ?> Custom Post Type (there are other plugins for it), because Custom Post Type has native support for hierarchy and ideally, it\s better then using default Post Type as hierarchy. However, if you are sure you need this our plugin, go on... )', 'add-hierarchy-parent-to-post'); ?>

plugin_URL.'/assets/media/parent-choose.png" title="sreenshot" target="_blank">this screenshot. Without this field, plugin can\'t work at all, so the option is not changeable. This option guarantees that wordpress native functions can correctly determine the child-parent post relations (So, posts can have "parent" field set in database). However, that doesnt guarentee the HIERARCHIED URLS will work - that is another subject (see below).', 'add-hierarchy-parent-to-post'); ?>

site.com/parent/child instead of site.com/child (Note, in "Settings>Permalinks" the structure should contain %postname%, otherwise this won\'t work).', 'add-hierarchy-parent-to-post'); ?>

Note,you see how limited capabilities does this plugin have. I couldn\'t find any better solution yet. So, for more reliability, you might also want to check Remove Base Slug from Custom Post Type, where you should create a new custom post type (name whatever you want) and then remove slug from that custom-post-type, and they will function like native "posts", but with better flexibility for hierarchy (the only drawback of using custom post types instead of native "post" types, is that some kind of 3rd party themes and plugins developers doesnt always (unfortunately!) include the support for custom post types and they only support native "page" or "post". However, if that\s not a problem for your case, then that plugin will help you).', 'add-hierarchy-parent-to-post'); ?>

pro_field();?>>

Permalinks page! Then on the front-end, refresh page once (with clicking Ctrl+F5) and new rules will start work. After that, also check if your link works correctly (feed,rss,attachments and categories).', 'add-hierarchy-parent-to-post' ), (is_network_admin() ? 'javascript:alert(\'You should go to specific sub-site permalink settings\'); void(0);' : admin_url("options-permalink.php")) ) ;?>

'mainsubmit-button'] ); ?> plugin_slug); ?>
settings_page_part("end"); } } // End Of Class $GLOBALS[__NAMESPACE__] = new PluginClass(); } // End Of NameSpace ?>