Change subcategory URL(slug) in Wordpress - php

I have problem with slug(URL) in category/subcategory. Now i have: http://my-page.pl/animal-category/animal-subcategory. How can i delete "animal-category" for every subcategory ?
It should look like that:
http://my-page.pl/animal-category/
http://my-page.pl/animal-subcategory/
http://my-page.pl/animal-subcategory/single-page
Maybe it's simple question, but I cant find answer anywhere :)

Check below code it will help you
// Add 'cat_redirect' query variable in query_vars
add_filter('query_vars', 'no_parent_cat_query_vars');
function no_parent_cat_query_vars($query_vars) {
$query_vars[] = 'cat_redirect';
return $query_vars;
}
// Redirect if 'cat_redirect' is set
add_filter('request', 'no_parent_cat_request');
function no_parent_cat_request($query_vars) {
if(isset($query_vars['cat_redirect'])) {
$cat_link = trailingslashit(get_option( 'home' )) . user_trailingslashit( $query_vars['cat_redirect'], 'category' );
status_header(301);
header("Location: $cat_link");
exit();
}
return $query_vars;
}
// Remove category
add_filter('category_link', 'category_url_without_parent',1000,2);
function category_url_without_parent($cat_link, $cat_id)
{
$category = &get_category( $cat_id );
if ( is_wp_error( $category ) ) return $category;
$catname = $category->slug;
$cat_link = trailingslashit(get_option( 'home' )) . user_trailingslashit( $catname, 'category' );
return $cat_link;
}
// Add custom category rewrite rule
add_filter('category_rewrite_rules', 'remove_category_parent_rule');
function remove_category_parent_rule($cat_rewrite) {
global $wp_rewrite;
$cat_rewrite=array();
$cat_list=get_categories(array('hide_empty'=>false));
foreach($cat_list as $category) {
$catname = $category->slug;
$cat_rewrite['('.$catname.')/(?:feed/)?(feed|rdf|rss|rss2|atom)/?$'] = 'index.php?category_name=$matches[1]&feed=$matches[2]';
$cat_rewrite['('.$catname.')/page/?([0-9]{1,})/?$'] = 'index.php?category_name=$matches[1]&paged=$matches[2]';
$cat_rewrite['('.$catname.')/?$'] = 'index.php?category_name=$matches[1]';
}
$old_base = $wp_rewrite->get_category_permastruct();
$old_base = str_replace( '%category%', '(.+)', $old_base );
$old_base = trim($old_base, '/');
$cat_rewrite[$old_base.'$'] = 'index.php?cat_redirect=$matches[1]';
return $cat_rewrite;
}

Related

Wordpress Replace words in already existed Posts

I have multiple words that i need to replace on posts that they are already added on the WordPress, but I don't want to change the full content, I need only the WordPress post output.
I have this code but is not working ... and I can't find how WordPress working about this ...
function SC_Replace_Words_On_Posts() {
$Replace_Words_Array = array(
'aaa' => 'aa',
);
if( isset($_REQUEST['post_id']) ) {
$Post_ID = $_REQUEST['post_id'];
} else {
$Post_ID = false;
}
$Post_Content = get_post_field('post_content', $Post_ID);
if($Post_Content != '' && is_array($Replace_Words_Array) && !empty($Replace_Words_Array)) {
foreach($Replace_Words_Array as $Find_Word => $Replace_Word) {
$Post_Content = SC_replaceWithCase($Find_Word, $Replace_Word, $Post_Content);
}
}
return $post;
}
add_filter("wp_insert_post_data", "SC_Replace_Words_On_Posts");

Creating a wordpress virtual page with a function and page template

I'm trying to create a virtual contact page on wordpress. All the necessary data will be stored in a page template. But in my function I don't know how to link to the file.
When the user does to domain.com/contact I would like to redirect him to the contact.php file.
So far I got this function to work and show content from this line $post->post_content = 'page template: contact.php'; but I would like to show the content from templates/contact.php
add_filter( 'the_posts', 'generate_contact_page', -10 );
function generate_contact_page( $posts ) {
global $wp, $wp_query;
$url_slug = 'contact'; // URL slug of the contact page
if ( ! defined( 'CONTACT_PAGE' ) && ( strtolower( $wp->request ) == $url_slug ) ) {
// stop interferring with other $posts arrays on this page (only works if the sidebar is rendered *after* the main page)
define( 'CONTACT_PAGE', true );
// create a contact virtual page
$post = new stdClass;
$post->post_author = 1;
$post->post_name = $url_slug;
$post->guid = home_url() . '/' . $url_slug;
$post->post_title = 'Contact page';
$post->post_content = 'page template: contact.php';
$post->ID = -999;
$post->post_type = 'page';
$post->post_status = 'static';
$post->comment_status = 'closed';
$post->ping_status = 'open';
$post->comment_count = 0;
$post->post_date = current_time( 'mysql' );
$post->post_date_gmt = current_time( 'mysql', 1 );
$posts = NULL;
$posts[] = $post;
// make wpQuery believe this is a real page too
$wp_query->is_page = true;
$wp_query->is_singular = true;
$wp_query->is_home = false;
$wp_query->is_archive = false;
$wp_query->is_category = false;
unset( $wp_query->query[ 'error' ] );
$wp_query->query_vars[ 'error' ] = '';
$wp_query->is_404 = false;
}
return $posts;
}
How can I achieve something like this? Maybe you know a better solution ?
So for template output you can try this function
function get_template_output($slug = '', $name = '') {
ob_start();
get_template_part($lug, $name);
return ob_get_clean();
}
And then to assign content you will use
$content = get_template_output('templates/', 'contact');

if is amp change internal links to amp version (WordPress)

We use WordPress and would like to link amp to amp if the linked page has an amp version. We have amp structured like that: test.de/test/amp
Unfortunately this code in my functions.php isnt applying to links hard-coded inside of the post content. What do I have to change, so its working for every internal link:
add_filter( 'post_link', function( $url, $post ) {
static $recursing = false;
if ( $recursing ) {
return $url;
}
$recursing = true;
if ( ! function_exists( 'post_supports_amp' ) || ! post_supports_amp( $post ) ) {
return $url;
}
if ( function_exists( 'is_amp_endpoint' ) && is_amp_endpoint() ) {
$url = amp_get_permalink( $post->ID );
}
$recursing = false;
return $url;
}, 10, 2 );
At the moment its also applying to the canonical link, which is really bad for seo. How to prevent this?
Add these functions to your theme's 'functions.php'.
/* post link filter */
add_filter( 'post_link', 'change_amp_url', 10, 2 );
function change_amp_url( $url, $postobj ) {
static $recursing = false;
if ( $recursing ) {
return $url;
}
$recursing = true;
if ( function_exists( 'is_amp_endpoint' ) && is_amp_endpoint() ) {
if ( function_exists( 'post_supports_amp' ) && post_supports_amp( $postobj ) ) {
$url = amp_get_permalink( $postobj->ID );
}
}
$recursing = false;
return $url;
}
/* content link filter */
add_filter( 'the_content', 'change_amp_url_content' );
function change_amp_url_content($content)
{
$dom = new DOMDocument();
$dom->loadHTML($content);
$tags = $dom->getElementsByTagName('a');
foreach ($tags as $tag) {
$link = $tag->getAttribute('href'); // original url
$extralink = '';
if(stristr($link,'#')) {
$pagelinktemp = explode("#",$link);
$pagelink = $pagelinktemp[0];
$extralink = '#'.$pagelinktemp[1];
} else {
$pagelink = $link;
}
if($pagelink!="") {
$postid = url_to_postid($pagelink);
$postobj = get_post($postid); // getting appropriate post object
if($postobj) {
$newlink = change_amp_url( $pagelink, $postobj ); //new url
}
else {
$newlink = $link;
}
}
else {
$newlink = $link;
}
if($link != $newlink) // change if only links are different
{
$content = str_replace($link, $newlink.$extralink, $content);
}
}
return $content;
}
/* override canonical link */
add_filter( 'wpseo_canonical', 'amp_override_canonical' );
function amp_override_canonical($url) {
if ( substr($url,-4)=="/amp" ) {
$url = substr($url,0,-4);
}
return $url;
}
The first function will provide the AMP URL if exists.
The second one will loop through each URL in the content and change to AMP URL if valid.
The last one will rewrite the canonical URL that displayed via Yoast SEO plugin.
If you want to replace hardcoded links inside of your post content I would suggest you use the "the_content" filter for wordpress.
https://codex.wordpress.org/Plugin_API/Filter_Reference/the_content
add_filter( 'the_content', 'filter_function_name' )
From this you should be able to regular expression match the link and append /amp to it.
Pseudo code example:
function my_the_content_filter($content)
{
if (function_exists('is_amp_endpoint') && is_amp_endpoint()) {
$patterns = array(
//patterns
);
$replacements = array(
//replacements
);
$content = preg_replace($patterns, $replacements, $content);
}
return $content;
}
add_filter('the_content', 'my_the_content_filter');
I have tested the code submitted by Outsource WordPress, and in general it works fine but the 'amp_override_canonical function overwrites all the urls of the page removing the /amp.
I have made some changes to this piece of code but they do not work as I expect. It seems that the 'wpseo_canonical' function is being invoked in a different context.
add_filter( 'wpseo_canonical', 'amp_override_canonical' );
function amp_override_canonical($url) {
if ( substr($url,-4)=="/amp" ) {
$url = substr($url,0,-4);
}
return $url;
}

2 Layouts for a WooCommerce shop

I have to categories named "Collectie" and "Shop", what I want is different layouts for the children of both categories.
I already tried this with the template_include function like this:
function lab5_template_include( $template ) {
if ( category_has_children('collectie')) {
$template = get_stylesheet_directory() . '/woocommerce/archive-product-collectie.php';
}elseif ( is_product_category('shop')) {
$template = get_stylesheet_directory() . '/woocommerce/archive-product-shop.php';
}
return $template;
}
How do I do that?
EDIT
I solved it with the solution from https://wordpress.org/support/topic/different-page-layouts-for-category-vs-subcategory
i added the next lines to taxonomy-product_cat.php
// We need to get the top-level category so we know which template to load.
$get_cat = $wp_query->query['product_cat'];
// Split
$all_the_cats = explode('/', $get_cat);
// How many categories are there?
$cat_count = count($all_the_cats);
//
// All the cats say meow!
//
// Define the parent
$parent_cat = $all_the_cats[0];
// Collectie
if ( $parent_cat == 'collectie' ) woocommerce_get_template( 'archive-product-collectie.php' );
// Shop
elseif ( $parent_cat == 'shop' ) woocommerce_get_template( 'archive-product.php' );
I think you'd be better off running a while loop to determine the parent level category name. Then you can match it against the different parent categories you want to display differently.
edit lab5_template_include() should use is_product_category() instead of is_product_taxonomy() which returns true on product category and tag archives.
function lab5_template_include( $template ) {
if( is_product_category()){
$slug = get_query_var('product_cat');
$cat = get_term_by( 'slug', $slug, 'product_cat' );
$catParent = so_top_product_category_slug($cat);
// locate the new templates
if ( 'collectie' == $catParent ) {
$new_template = locate_template( array( 'woocommerce/archive-product-collectie.php' ) );
} elseif ( 'shop' == $catParent ) ) {
$new_template = locate_template( array( 'woocommerce/archive-product-shop.php' ) );
}
// set the new template if found
if ( '' != $new_template ) {
$template = $new_template ;
}
}
return $template;
}
add_filter('template_include', 'lab5_template_include', 20 );
edit bug fixes and improved efficiency of so_top_product_category_slug(). Now tested and working.
// get the top-level parent product category from a term object or term slug
function so_top_product_category_slug($cat) {
if( is_object( $cat ) ){
$catid = $cat->term_id;
} else {
$cat = get_term_by( 'slug', $cat, 'product_cat' );
$catid = $cat->term_id;
}
$parentId = $cat->parent;
$parentSlug = $cat->slug;
while ($parentId > 0) {
$cat = get_term_by( 'id', $parentId, 'product_cat' );
$parentId = $cat->parent; // assign parent ID (if exists) to $catid
$parentSlug = $cat->slug;
}
return $parentSlug;
}

Wordpress Widget not saving

I'm trying to save a simple widget, however everytime I hit save, it does not save the values. Instead the form is refreshed to a default value.
The code is below.
What I have found is that the value of $instance in the update() function is an empty array i.e. array() why is this??
<?php
defined('ABSPATH') or die("Cannot access pages directly.");
defined("DS") or define("DS", DIRECTORY_SEPARATOR);
add_action( 'widgets_init', create_function( '', 'register_widget("Page_Widget");' ) );
add_action( 'admin_head', 'page_widget_admin_head' );
$pw_class = new Page_Widget();
add_action( 'wp_ajax_nopriv_pw_get_option', array($pw_class, 'get_options'));
add_action( 'wp_ajax_pw_get_option', array($pw_class, 'get_options'));
function page_widget_admin_head()
{
if(basename($_SERVER['SCRIPT_NAME']) != 'widgets.php'){return false; }
echo '<style> .titler { width:80px; display:inline-block; }</style>';
echo '<script type="text/javascript">
jQuery(function($){
$(".post_type_select").live("change", function(){
the_opt = $(this).val();
el = $(this);
$.post(ajaxurl, "action=pw_get_option&pw_post_type="+the_opt, function(data){
el.siblings(".posts_select").html(data);
})
});
});</script>';
}
/**
*
* #author byrd
* Document Widget
*/
class Page_Widget extends WP_Widget
{
/**
* Constructor
*
* Registers the widget details with the parent class
*/
function __construct()
{
// widget actual processes
parent::__construct( $id = 'page_widget', $name = 'Page Widget', $options = array( 'description' => 'A Widget for grabbing page ids' ) );
}
function form($instance)
{
// outputs the options form on admin
$post_type_str = '<span class="titler">Post Type: </span><select name="pw_post_type" class="post_type_select">';
$post_types = get_post_types(array('public' => true),' objects');
$i = 1;
$pw_post_type = '';
$pw_post_id = '';
error_log(var_export($instance, true));
if ( $instance ) {
$pw_post_type = esc_attr( $instance[ 'pw_post_type' ] );
$pw_post_id = esc_attr( $instance[ 'pw_post_id' ] );
}
foreach ($post_types as $post_type ) {
$name = $post_type->labels->name;
$var = $post_type->name;
if($i == 1){$first = $var; }
if($pw_post_type == $var){$selected = 'selected="selected"'; }else{$selected = ''; }
$post_type_str .= '<option '.$selected.' value="'.$var.'">'. $name. '</option>';
$i++;
}
$options = $this->get_options($first, $pw_post_id);
$post_type_str .= '</select><br/><span class="titler">Post Name: </span><select name="pw_post_id" class="posts_select">'.$options.'</select>';
echo $post_type_str;
}
function get_options($post_type = false, $pw_post_id = '', $ajax = false)
{
if(!$post_type){ $post_type = $_POST['pw_post_type']; $ajax = true; }
$args = array('numberposts' => -1, 'post_type' => $post_type);
$str = '';
$posts_array = get_posts( $args );
foreach( $posts_array as $post )
{
if($pw_post_id == $post->ID){$selected = 'selected="selected"'; }else{ $selected = ''; }
$str .= '<option '.$selected.' value="'.$post->ID.'">'.$post->post_title.'</option>';
}
if($ajax){ echo $str; exit(); }
else{ return $str; }
}
function update($new_instance, $old_instance)
{
error_log(var_export($new_instance, true));
error_log(var_export($old_instance, true));
// processes widget options to be saved
$instance = wp_parse_args($old_instance, $new_instance);
return $new_instance;
}
function widget($args, $instance)
{
// outputs the content of the widget
}
}
Looks like you asked this a while ago, but I'll answer in case others follow along.
Make sure you're using:
$field_name = $this->get_field_name('your_field_name');
when creating field names for your widget form items. The field names need to conform to WordPress' naming conventions. Otherwise, you'll get nothing back from the form post.
Change your class name which is
class Page_Widget extends WP_Widget
to this
class WP_Widget_Page_Widget extends WP_Widget
and also change this line
add_action( 'widgets_init', create_function( '', 'register_widget("Page_Widget");' ) );
to
add_action( 'widgets_init', create_function( '', 'register_widget("WP_Widget_Page_Widget ");' ) );
This will work insaAllah.

Categories