WordPress: Kategorie-Liste scrollt nicht mehr [Lösung]

Seit dem Update auf WordPress 6.6 lassen sich Kategorie-Listen im Admin-Bereich nicht mehr scrollen, Stattdessen werden sie komplett angezeigt – also alle Kategorien untereinander in einer alphabetischen Liste.

Wenn man nur 3-4-5 Kategorien verwendet mag das nicht weiter stören. Wenn man in seiner WordPress-Website aber dutzende oder sogar hunderte Kategorien verwendet kann das dazu führen, dass sich die Kategorien kaum noch sinnvoll nutzen lassen. Die Eingabemaske wird entsprechend der langen Kategorie-Liste in die Länge gezogen – und wer das Kategorie-Widget aus der rechten Seitenleiste in den Hauptbereich z.B. unterhalb des Texteditors gezogen hat ein Problem.

Ich hatte genau diese Anordnung – also die Kategorie-Liste unterhalb des WYSIWYG-Editors – gefolgt von einer Reihe eigener Eingabefelder, die ich über Advanced Custom Fields Pro (ACF) angelegt hatte. Nach dem Update wurden diese ACF-Felder nun von der ausgeklappten Kategorie-Liste in fast unerreichbare Tiefen hinunter gedrückt. Ein Zustand, den man vielleicht ein paar Tage lang ignorieren kann – der aber ein flüssiges Arbeiten mit WordPress fast unmöglich macht.

Ich muss dazu sagen, dass ich „natürlich“ den Classic Editor bevorzuge – und dass dieses Problem offenbar nur im Classic Editor auftritt. So lautet eine der Empfehlungen dann auch, nicht den Classic Editor zu nutzen. Diese Option scheidet für mich aber aus, da ich es gewohnt bin, meine EIngabemasken selbst zu bauen und so zu gestalten, wie ich es möchte.

Im WordPress-Forum fand ich dann eine einfache Lösung für das Problem: per CSS kann man die Kategorie-liste dazu bringen, sich so zu verhalten, wie vor dem Update – also so, dass sich alle Kategorien scrollen lassen.

Der CSS-Schnippsel würd eregulär über ein Stylesheet funktionieren, wenn man denn für den Administrationsbereich ein Stylesheet definiert hat. Das ist sicherlich eher selten der Fall. Per PHP lässt sich der CSS-Schnippsel aber auch einfach über die functions.php in den Admin-Bereich einbauen:

add_action('admin_head', 'admin_css_code');
function admin_css_code()
{
echo '<style>

.categorydiv div.tabs-panel
{
max-height: 200px;
}

</style>';
}

Der Code stammt ursprünglich von dem Nutzer @vinodkkumar –– allerdings waren bei seinem Lösungsvorschlag leider die Anführungszeichen falsch formatiert. Ich habe den Code-Schnippsel sozusagen repariert – einfach per copy-paste in die funstions-php einfügen und schon lässt sich die Kategorie-Liste wieder scrollen.

Hier die Diskussion im WordPress-Forum:
wordpress.org/support/topic/category-list-no-longer-scrolling/

Worpress Suche-Formular: Submit-Button-Text anpassen

Eigentlich wollte ich nur den Text des Submit-Buttons des Standard-Suche-Formulars anpassen. Eigentlich. Das ist aber offenbar gar nicht so einfach, denn das Suche-Formular wird mir einer recht einfach gestrickten Funktion aufgerufen, über die sich zumindest meines Wissens nach der Text des Submit-Buttons leider nicht anpassen lässt.

Hier die Standard-Funktion, über die man das Suche-Fenster an beliebiger Stelle in einem WordPress-Template platzieren kann:

get_search_form();

Es gibt natürlich eine Reihe von Plugins, die genau das machen – die also eine einfache Möglichkeit bieten, die verschiedenen Details des Suche-Formulars zu bearbeiten – also auch den text des Submit-Buttons. Aber warum sollte man ein weiteres Plugin installieren, wenn man doch nur den Text Submit-Buttons anpassen möchte?

Stattdessen können wir auch relativ einfach die Funktion get_search_form() überschreiben und mit unserem eigenen Code ergänzen.

/* custom search form */

function custom_search_form( $form ) {
$form = '
<section class="search"><form role="search" class="search-form" method="get" id="search-form" action="' . home_url( '/' ) . '" >
<label class="screen-reader-text" for="s">' . __( 'Search:' ) . '</label>
<input type="search" class="search-field" value="' . get_search_query() . '" name="s" id="s" placeholder="…" />
<input type="submit" class="search-submit" id="searchsubmit" value="'. esc_attr__( 'Search' ) .'" />
</form></section>
';

return $form;
}
add_filter( 'get_search_form', 'custom_search_form', 40 );

Das Script muss einfach in der funtions-php des aktiven Themes platziert werden – und schon lässt sich der text des Submit-Buttons ändern.

Der Code basiert auf der Funktion custom_search_form, die ich unter der Überschrift ‚Custom WordPress Search Form with a Function‘ bei nicolaslule.com gefunden habe: nicolaslule.com/how-to-customize-the-search-form-in-wordpress/

Auf der Seite finden sich ein paar weitere hilfreiche Tipps und Tricks – zum Beispiel, wie man die Suche auf einen bestimmten Post Type beschränkt – oder auch, wie man den Submit-Button mit einem Icon ersetzen kann.

WordPress Benutzernamen verstecken

Webseiten, die mit WordPress gebaut sind, werden verhältnismäßig oft Ziel von Hacker-Angriffen – insbesondere von sogn. Brute Force Angriffen. Dafür versucht der Angreifer, durch eine manchmal sehr große Anzahl von Login-Versuchen, das Passwort eines Nutzers oder sogar eines Administrators zu erraten. In den meisten Fällen werden diese Angriffe von Bots durchgeführt.

Es gibt Dinge, die man tun kann, um solche Brute Force Angriffe abzuwehren. Ganz oben auf der Liste möglicher Abwehrmaßnahmen sind Sicherheits-Plugins, die solche Angriffe registrieren und dann die entsprechende IP-Adresse oder den Nutzernahmen für eine gewisse Zeit blockieren. EIn Erraten des Passworts ist dann zwar immernoch möglich, dauert aber entscheidend länger.

Woher haben Angreifer die Nutzernamen?

Angrifer nutzen häufig den Umstand aus, dass sich die Nutzernamen einer WordPress Installation recht einfach herausfinden lassen. Dazu muss der Angreifer lediglich die Autorenseite aufrufen. Aber wie ruft ein potentieller Hacker die Autorenseite auf, ohne den Login-Namen zu kennen? Die Antwort liegt in der Systematik, wie WordPress eigentlich alle Seiten verwaltet: über die URL /?author=1 wird man beispielsweise auf die Profilseite des Hauptaccounts weitergeleitet – der Name des Hauptnutzers, in den meisten Fällen der Nutzer mit Administrator- und somit allen Rechten.

WordPress Profilseiten und Benutzernamen per Code verstecken

Mit folgendem Script wird genau diese Weiterleitung unterbunden:


/* hide author archive page */ 

add_action('template_redirect', 'my_custom_disable_author_page');

function my_custom_disable_author_page() {
    global $wp_query;

    if ( is_author() ) {
        // Redirect to homepage, set status to 301 permenant redirect. 
        // Function defaults to 302 temporary redirect. 
        wp_redirect(get_option('home'), 301); 
        exit; 
    }
}

Dieses Skript muss in die Datei function.php des aktiven Themes oder Child-Themes eingesetzt werden – dann werden alle Anfragen auf die URL /?author=x auf die Startseite weitergeleitet.

Das Skript bietet natürlich keine 100%-ige Sicherheit gegen Brute Force Angriffe – sollte aber als Mindest-Maßname in jedes WordPRess-Theme einegesetzt werden – zumindest dann, wenn man auf die Profilseiten bzw. Autorenseiten verzichten kann.

Benutzernamen in der REST API

Neben der oben aufgeführten ‚Quelle‘ gibt es noch die REST API, die Nutzernamen und somit Login-Namen nach außen kommuniziert.

Grundsätzlich kann die REST API natürlich sehr hilfreich sein, wenn man möchte, dass Inhalte der Website nach außen kommuniziert und somit abrufbar werden. Aber bei Nutzernamen wird aus meiner Sicht aus diesem Feature ein Bug.

Zum Testen einfach mal die folgende URL Aufrufen: „/wp-json/wp/v2/users/1“

Ich nutze Solid Security Pro – und darüber lässt sich diese Sicherheitslücke ziemlich einfach schließen. Dazu muss man an folgender Stelle die Option „Restricted Access“ auswählen:

„Solid Security Pro > Settings > Advanced > WordPress Tweaks > REST API“

Und schon erscheint anstelle von Nutzer-ID, Nutzer-Name, Nutzer-Slug etc. lediglich der folgende Hinweis:

code: "itsec_rest_api_access_restricted"
message: "You do not have sufficient permission to access this endpoint. Access to REST API requests is restricted by Solid Security settings."
status: 401

Und fertig ist die Hütte.

Aktive Autorenseiten zeigen, inaktive Autoren und Nutzernamen verbergen

Man muss natürlich nicht immer gleich alles ausschalten, verstecken und deaktivieren. Die Autoren-Archivseiten können natürlich auch eine schöne Möglichkeit sein, alle Inhalte eines Autoren oder einer Autorin übersichtlich auf einer Seite anzeigen zu lassen. Und so war es ja auch ursprünglich gedacht. Aber immer wieder gibt es neben den aktiven Autoren auch WordPress-Nutzer, die keine Artikel veröffentlichen und bei denen die Archivseite dann dementsprechend leer ist – und insofern keinen Sinn macht. Hier stellt die Preisgabe des Nutzernamens, der ja identisch mit dem Login-Namen ist, ein Sicherheitsrisiko dar, das sich mithilfe von Solid Security Pro sehr einfach ausschalten lässt.

In SolidWP Pro gibt es eine weitere EInstellung, mit der man Archivseiten von inaktiven Autoren deaktivieren kann. Diese Funktion findet sich hier:

„Solid Security Pro > Settings > Advanced > WordPress Tweaks > Users >

Alle Autorenseiten mit einem Plugin deaktivieren

Zu guter Letzt sei noch die Holzhammermethode erwähnt: mit dem kostenlosen Plugin Disable Author Archives kann man ganz einfach und schnell alle Autorenseiten „abschalten“. Anstelle der Archivseite wird dann ein 404-Fehler ausgegeben

Externe Links automatisch in neuem Fenster öffnen [jQuery-Snippet]

Externe Links automatisch in neuem Fenster öffnen [jQuery-Snippet]

Screenshot / Montage: T.Bortels/cpu20.de

Auf wohl so gut wie jeder Webseite sind externe Links zu finden. Und häufig wird gewünscht, dass sich externe Links in einem neuen Fenster öffenen –zum Beispiel um die Besucher der Webseite über einen solchen externen Link nicht zu verlieren. Über die Target-Anweisung „_blank“ lässt sich das auch ganz komfortabel bewerkstelligen. Doch wie kann man sicherstellen, dass sich immer alle externen Links in einem neuen Fenster öffnen?

Mal werden externe Links im CMS komfortabel über eigene Eingabefelde verwaltet, aber häufig sind extrne Links im Content der Seite zu finden – im Fließtext. Die Links werden dann über den Text-Editor angelegt – und da kommt es immer wieder vor, dass es die Redaktion versäumt, den Link als externen Link zu markieren bzw. das Häkchen für die Target-Anweisung „_blank“ zu setzen.

Mithilfe den folgenden kleinen jQuery Code Schnippsels läßt sich dieses Problem komfortabel beseitigen:

<script>
jQuery("html a[href^=http]").each(function(){
    if(this.href.indexOf(location.hostname) == -1) {
        jQuery(this).attr({
            target: "_blank",
            title: "Opens in a new window"
        });
    }
});
</script>

Zuerst such das Skript nach allen Linkelementen, die „http“ enthalten. Lokale Links, die direkt mit dem Top-Verzeichnis und nicht mit dem Domainnamen beginnen, werden also von vorneherein ignoriert. In der zweiten Zeile wird geprüft, ob der angegebene Hostname bzw. die im Link aufgeführe Domain von der DOmain abweicht, auf der sich das Skript befindet. Der nachfolgende Code wird also nur auf Links angewendet, die auf andere Webseiten verweisen, als die eigene.

In den folgenden zwei Zeilen wird den Links die Target-Anweisung „_blank“ sowie ein Title-Tag mit dem Hinweis „Opens in a new window“ hinzugefügt. Damit haben wir das Grundproblem bereis behoben: alle externen Links werden nun in einem neuen Fenster geöffnet.

Im folgenden kommen noch zwei weitere Code-Schnippsel hinzu, die ggf. ganz praktisch sein könnnen, wenn man das Design externer Links per CSS anders gestalten möchte, als interne Links.Diesmal bezieht sich das Skript allerdings exemplarisch nicht auf den gesamten HTML Code der Seite, sondern ausschließlich auf die Inhalte, die sich innerhalb des DIV-Containers mit der Klasse „entry-content“ befinden.

Der erste Teil bleibt  also wie er ist – nur die Auswahl wurde hier exemplarisch auf den DIV-Container mit der Klasse „entry-content“ eingeschränkt.

Es folgt ein Einzeiler, der allen externen Links bzw. allen Links, die sich in einem neuen Fenster öffnen, die CSS-Klasse „external“ hinzufügt. Somit könnte der Link bereits jetzt ein eigenes Design erhalten.

Um die Sache noch ein wenig komfortabler zu machen wird nun in dem dritten Code-Schnippsel noch ein SPAN-Container in den Link eingebaut. Somit ließe sich beispielweise durch den ::before-Selector oder den ::after-Selector dem Link ein Pictogramm hinzufügen, das visuell darauf hinweist, dass man bei Klick auf den Link die Seite in einem neuen Fenstern verlässt.

<script>
jQuery(".entry-content a[href^=http]").each(function(){
    if(this.href.indexOf(location.hostname) == -1) {
        jQuery(this).attr({
            target: "_blank",
            title: "Opens in a new window"
        });
    }
});

jQuery('.entry-content a[target="_blank"]').addClass('external');


jQuery('.entry-content a.external').each(function(){
    jQuery(this).each(function(){
      jQuery(this).wrapInner('<span></span>');
    });      
});
</script>

Und das wars schon. So lassen sich externe Links mithilfe eines kleinen jQuery-Snippets automatisch in neuem Fenster öffnen.

SEOPress Metabox unter die ACF Felder bewegen

SEOPress unter die ACF Felder bewegen:

/* move SEOPress meta box down */
add_action( 'add_meta_boxes', function() {
global $wp_meta_boxes;

$post_type = 'page';

// Get seopress meta boxes
$seopress_meta_box = $wp_meta_boxes[$post_type]['normal']['high']['seopress_cpt'];
$seopress_analysis_meta_box = $wp_meta_boxes[$post_type]['normal']['high']['seopress_content_analysis'];

unset( $wp_meta_boxes[$post_type]['normal']['high']['seopress_cpt'] );
unset( $wp_meta_boxes[$post_type]['normal']['high']['seopress_content_analysis'] );

// Move it to 'advanced' location with 'low' priority.
if ( empty( $wp_meta_boxes[$post_type]['advanced'] ) ) {
$wp_meta_boxes[$post_type]['advanced'] = [];
}
if ( empty( $wp_meta_boxes[$post_type]['advanced']['low'] ) ) {
$wp_meta_boxes[$post_type]['advanced']['low'] = [];
}
$wp_meta_boxes[$post_type]['advanced']['low']['seopress_cpt'] = $seopress_meta_box;
$wp_meta_boxes[$post_type]['advanced']['low']['seopress_content_analysis'] = $seopress_analysis_meta_box;

}, 99 );

Wenn die SEOPress Metabox gleich bei mehreren Content Typen (z.B. auch bei Custom Post Types)  unterhalb der ACF-Felder bewegen will muss der Code lediglich in einen entsprechenden foreach-Loop gekapselt werden – die Variable ‚post_type‘ wird durch den Array ‚post_types‘ ersetzt:

/* move SEOPress meta box down */
add_action( 'add_meta_boxes', function() {
global $wp_meta_boxes;

$post_types = array('post','page','custon_post_type');

foreach($post_types as $post_type) {

// Get seopress meta boxes
$seopress_meta_box = $wp_meta_boxes[$post_type]['normal']['high']['seopress_cpt'];
$seopress_analysis_meta_box = $wp_meta_boxes[$post_type]['normal']['high']['seopress_content_analysis'];

unset( $wp_meta_boxes[$post_type]['normal']['high']['seopress_cpt'] );
unset( $wp_meta_boxes[$post_type]['normal']['high']['seopress_content_analysis'] );

// Move it to 'advanced' location with 'low' priority.
if ( empty( $wp_meta_boxes[$post_type]['advanced'] ) ) {
$wp_meta_boxes[$post_type]['advanced'] = [];
}
if ( empty( $wp_meta_boxes[$post_type]['advanced']['low'] ) ) {
$wp_meta_boxes[$post_type]['advanced']['low'] = [];
}
$wp_meta_boxes[$post_type]['advanced']['low']['seopress_cpt'] = $seopress_meta_box;
$wp_meta_boxes[$post_type]['advanced']['low']['seopress_content_analysis'] = $seopress_analysis_meta_box;

}
}, 99 );

 

In Anlehnung an „WordPress: Change meta box location“
https://deluxeblogtips.com/wordpress-change-meta-box-location/

Siehe auch „Moving meta boxes in admin“
https://wordpress.stackexchange.com/questions/166825/moving-meta-boxes-in-admin

Und auch hier: „How to reorder meta box position?“
https://wordpress.stackexchange.com/questions/57897/how-to-reorder-meta-box-position

Google Analytics aus dem Dashboard entfernen

SEOPress bringt ein Feature mit, dass sich manchmal wie ein Bug anfühlen mag. Zu der ohnehin schon langen Liste von Dashboard Widgets wird automatisch ein Widget für Google Analytics hinzugefügt – egal, ob man den Dienst nutzt, oder nicht.

Mit einer Zeile Code in der functions.php des aktiven Themes (oder Child-Themes) lässt sich dieses Feld einfach ausblenden:

/**
* Remove Google Analytics Widget in WordPress Dashboard 
*
**/

add_filter( 'seopress_ga_dashboard_widget', '__return_false' );

Hier auf der SEOPress-Homepage im Bereich Support zu finden:
www.seopress.org/support/hooks/remove-google-analytics-widget-in-wordpress-dashboard/