removed old file
This commit is contained in:
408
ai-translate.php
408
ai-translate.php
@@ -1,408 +0,0 @@
|
||||
<?php
|
||||
ob_start(); // Sofortiges Output Buffering
|
||||
|
||||
/**
|
||||
* Plugin Name: AI Translate
|
||||
* Description: Plugin zum Verwalten und Übersetzen von Beiträgen, Seiten und Custom Post Types (ohne AJAX, erweiterte Funktionen).
|
||||
* Version: 1.22
|
||||
* Author: Dein Name
|
||||
* License: GPL2
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verarbeitet Formular- und URL-Anfragen:
|
||||
* - Werden per POST ausgewählte Beiträge übermittelt, so werden diese (ohne Duplikate) zur bestehenden Auswahl hinzugefügt.
|
||||
* - Wird per GET der Parameter "remove" übergeben, so wird der entsprechende Eintrag entfernt.
|
||||
*
|
||||
* Alle relevanten GET‑Parameter (tab, paged, orderby, order, category) werden übernommen, sodass der Redirect
|
||||
* den aktuellen Zustand beibehält.
|
||||
* Falls bereits Output gesendet wurde, erfolgt der Redirect mittels JavaScript und Meta‑Refresh.
|
||||
*/
|
||||
function ait_handle_form_submissions() {
|
||||
$action_taken = false;
|
||||
$current_tab = isset($_GET['tab']) ? sanitize_text_field($_GET['tab']) : 'post';
|
||||
|
||||
// Alle relevanten Parameter übernehmen:
|
||||
$params = array(
|
||||
'tab' => $current_tab,
|
||||
'paged' => isset($_GET['paged']) ? intval($_GET['paged']) : 1,
|
||||
'orderby' => isset($_GET['orderby']) ? sanitize_text_field($_GET['orderby']) : 'modified',
|
||||
'order' => isset($_GET['order']) ? sanitize_text_field($_GET['order']) : 'desc',
|
||||
'category'=> isset($_REQUEST['category']) ? intval($_REQUEST['category']) : 0,
|
||||
);
|
||||
$redirect_url = add_query_arg( $params, admin_url('admin.php?page=ai-translate') );
|
||||
|
||||
// Beiträge hinzufügen (POST)
|
||||
if ( $_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['selected_posts']) && is_array($_POST['selected_posts']) ) {
|
||||
$new_posts = array_map( 'intval', $_POST['selected_posts'] );
|
||||
$current = get_option( 'ait_selected_posts', [] );
|
||||
$merged = array_unique( array_merge( $current, $new_posts ) );
|
||||
update_option( 'ait_selected_posts', $merged );
|
||||
$action_taken = true;
|
||||
}
|
||||
|
||||
// Einzelnen Eintrag entfernen (GET)
|
||||
if ( isset($_GET['remove']) ) {
|
||||
$remove_id = intval($_GET['remove']);
|
||||
$current = get_option( 'ait_selected_posts', [] );
|
||||
if ( ($key = array_search($remove_id, $current)) !== false ) {
|
||||
unset($current[$key]);
|
||||
update_option( 'ait_selected_posts', $current );
|
||||
$action_taken = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $action_taken ) {
|
||||
if ( headers_sent() ) {
|
||||
echo '<meta http-equiv="refresh" content="0; url=' . esc_url( $redirect_url ) . '">';
|
||||
echo '<script type="text/javascript">window.location.href="' . esc_js( $redirect_url ) . '";</script>';
|
||||
exit;
|
||||
} else {
|
||||
if ( ob_get_length() ) {
|
||||
ob_end_clean();
|
||||
}
|
||||
wp_redirect( $redirect_url );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fügt das Admin-Menü hinzu.
|
||||
*/
|
||||
function ait_add_admin_menu() {
|
||||
add_menu_page( 'AI Translate', 'AI Translate', 'manage_options', 'ai-translate', 'ait_admin_page', 'dashicons-translation', 25 );
|
||||
}
|
||||
add_action( 'admin_menu', 'ait_add_admin_menu' );
|
||||
|
||||
/**
|
||||
* Zeigt die Admin-Seite an.
|
||||
* Die Reihenfolge: Zuerst der Titel, dann die "Gespeicherte Auswahl" (direkt darunter), anschließend die Reiter, danach der Rest.
|
||||
*/
|
||||
function ait_admin_page() {
|
||||
ait_handle_form_submissions();
|
||||
$current_tab = isset($_GET['tab']) ? sanitize_text_field($_GET['tab']) : 'post';
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1>AI Translate</h1>
|
||||
<style>
|
||||
.wp-list-table .checkbox-column { width: 40px; }
|
||||
.selected-posts-box { margin-bottom: 20px; }
|
||||
.actions { margin-bottom: 20px; }
|
||||
.sortable a { text-decoration: none; }
|
||||
.sortable a.sorted-asc::after { content: " ▲"; }
|
||||
.sortable a.sorted-desc::after { content: " ▼"; }
|
||||
</style>
|
||||
<!-- Gespeicherte Auswahl direkt unter dem Titel -->
|
||||
<div class="selected-posts-box">
|
||||
<?php echo ait_get_selected_list_html( $current_tab ); ?>
|
||||
</div>
|
||||
|
||||
<!-- Übersetzen-Button nur anzeigen, wenn Auswahl nicht leer ist -->
|
||||
<?php
|
||||
$saved = get_option( 'ait_selected_posts', [] );
|
||||
if ( ! empty( $saved ) ) : ?>
|
||||
<div class="actions">
|
||||
<button id="translate-button" class="button button-primary">Übersetzen</button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Reiter -->
|
||||
<h2 class="nav-tab-wrapper">
|
||||
<a href="?page=ai-translate&tab=post" class="nav-tab <?php echo ($current_tab == 'post') ? 'nav-tab-active' : ''; ?>">Beiträge</a>
|
||||
<a href="?page=ai-translate&tab=page" class="nav-tab <?php echo ($current_tab == 'page') ? 'nav-tab-active' : ''; ?>">Seiten</a>
|
||||
<?php
|
||||
$custom_post_types = get_post_types( ['_builtin' => false], 'objects' );
|
||||
foreach ( $custom_post_types as $cpt ) {
|
||||
echo '<a href="?page=ai-translate&tab=' . esc_attr( $cpt->name ) . '" class="nav-tab ' . (($current_tab == $cpt->name) ? 'nav-tab-active' : '') . '">' . esc_html( $cpt->label ) . '</a>';
|
||||
}
|
||||
?>
|
||||
</h2>
|
||||
|
||||
|
||||
|
||||
<?php ait_display_table( $current_tab ); ?>
|
||||
</div>
|
||||
<?php
|
||||
ob_end_flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Erzeugt den HTML-Code für die "Gespeicherte Auswahl".
|
||||
* Die Titel werden fett (ohne Link) ausgegeben; es erscheint kein "Bearbeiten"-Link.
|
||||
*/
|
||||
function ait_get_selected_list_html( $current_tab ) {
|
||||
ob_start();
|
||||
$selected_posts = get_option( 'ait_selected_posts', [] );
|
||||
echo '<div>';
|
||||
echo '<h3>Gespeicherte Auswahl</h3>';
|
||||
if ( ! empty( $selected_posts ) ) {
|
||||
echo '<div id="selected-posts-list">';
|
||||
$titles = [];
|
||||
// Alle relevanten Parameter übernehmen, um den Zustand beizubehalten.
|
||||
$params = array(
|
||||
'tab' => $current_tab,
|
||||
'paged' => isset($_GET['paged']) ? intval($_GET['paged']) : 1,
|
||||
'orderby' => isset($_GET['orderby']) ? sanitize_text_field($_GET['orderby']) : 'modified',
|
||||
'order' => isset($_GET['order']) ? sanitize_text_field($_GET['order']) : 'desc',
|
||||
'category'=> isset($_GET['category']) ? intval($_GET['category']) : 0,
|
||||
);
|
||||
foreach ( $selected_posts as $post_id ) {
|
||||
$post = get_post( $post_id );
|
||||
if ( $post && ! empty( $post->post_title ) ) {
|
||||
$remove_params = $params;
|
||||
$remove_params['remove'] = $post_id;
|
||||
$remove_url = add_query_arg( $remove_params, admin_url( 'admin.php?page=ai-translate' ) );
|
||||
$titles[] = '<span class="selected-item" data-id="' . esc_attr( $post_id ) . '">'
|
||||
. '<strong>' . esc_html( $post->post_title ) . '</strong>'
|
||||
. ' <a class="remove-item" href="' . esc_url( $remove_url ) . '">[x]</a>'
|
||||
. '</span>';
|
||||
}
|
||||
}
|
||||
echo implode( '<br>', $titles );
|
||||
echo '</div>';
|
||||
} else {
|
||||
echo '<p>Keine Einträge ausgewählt.</p>';
|
||||
}
|
||||
echo '</div>';
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt für einen Beitrag alle Begriffe aus den hierarchischen Taxonomien zurück.
|
||||
*/
|
||||
function ait_get_post_categories( $post_id, $post_type ) {
|
||||
$taxonomies = get_object_taxonomies( $post_type, 'objects' );
|
||||
$category_names = [];
|
||||
foreach ( $taxonomies as $taxonomy ) {
|
||||
if ( $taxonomy->hierarchical ) {
|
||||
$terms = get_the_terms( $post_id, $taxonomy->name );
|
||||
if ( ! empty( $terms ) && ! is_wp_error( $terms ) ) {
|
||||
foreach ( $terms as $term ) {
|
||||
$category_names[] = $term->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $category_names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ermittelt die erste hierarchische Taxonomie für den Post Type.
|
||||
*/
|
||||
function ait_get_category_taxonomy( $post_type ) {
|
||||
$taxonomies = get_object_taxonomies( $post_type, 'objects' );
|
||||
foreach ( $taxonomies as $taxonomy ) {
|
||||
if ( $taxonomy->hierarchical ) {
|
||||
return $taxonomy->name;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Erzeugt einen sortierbaren Link.
|
||||
* Spalten, die sortierbar sein sollen, sind "Titel" und "Last Modified".
|
||||
* Jetzt wird auch der aktuelle Kategorienfilter übernommen, sodass sich der Filter nicht zurücksetzt.
|
||||
*/
|
||||
function ait_sort_link( $column_label, $column_key, $current_tab ) {
|
||||
$current_orderby = $_GET['orderby'] ?? 'modified';
|
||||
$current_order = $_GET['order'] ?? 'desc';
|
||||
$next_order = 'asc';
|
||||
$class = 'sortable';
|
||||
if ( $current_orderby === $column_key ) {
|
||||
if ( $current_order === 'asc' ) {
|
||||
$next_order = 'desc';
|
||||
$class .= ' sorted-asc';
|
||||
} else {
|
||||
$next_order = 'asc';
|
||||
$class .= ' sorted-desc';
|
||||
}
|
||||
}
|
||||
$category = isset($_REQUEST['category']) ? intval($_REQUEST['category']) : 0;
|
||||
$url = add_query_arg( [
|
||||
'orderby' => $column_key,
|
||||
'order' => $next_order,
|
||||
'tab' => $current_tab,
|
||||
'category' => $category,
|
||||
], admin_url( 'admin.php?page=ai-translate' ) );
|
||||
return '<a href="' . esc_url( $url ) . '" class="' . esc_attr( $class ) . '">' . esc_html( $column_label ) . '</a>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt eine Tabelle mit Beiträgen, Seiten oder Custom Post Types an.
|
||||
* Die Tabelle enthält:
|
||||
* - Eine Checkbox-Spalte
|
||||
* - Spalte "Titel": Fett dargestellter Link zum Beitrag (öffnet in neuem Tab) plus Statusanzeige (Privat/Entwurf) und einen "Bearbeiten"-Link.
|
||||
* - Spalte "Kategorie"
|
||||
* - Spalte "Last Modified": basierend auf dem Datum der letzten Änderung (Format: "YYYY/MM/DD at g:i a").
|
||||
* Die Tabelle ist sortierbar nach "Titel" und "Last Modified".
|
||||
* Die Pagination wird oben und unten angezeigt, jeweils rechtsbündig.
|
||||
*
|
||||
* Wichtig: Der Kategorien-Filter wird über ein separates GET-Formular geregelt – der Parameter "category" wird über $_REQUEST ausgelesen.
|
||||
*/
|
||||
function ait_display_table( $post_type ) {
|
||||
$selected_category = intval( $_REQUEST['category'] ?? 0 );
|
||||
$paged = max( 1, intval( $_GET['paged'] ?? 1 ) );
|
||||
$posts_per_page = 10;
|
||||
$orderby = $_GET['orderby'] ?? 'modified';
|
||||
$order = $_GET['order'] ?? 'desc';
|
||||
|
||||
$args = [
|
||||
'post_type' => $post_type,
|
||||
'posts_per_page' => $posts_per_page,
|
||||
'paged' => $paged,
|
||||
'post_status' => [ 'publish', 'private', 'draft' ],
|
||||
'orderby' => $orderby,
|
||||
'order' => strtoupper( $order ),
|
||||
];
|
||||
$category_tax = ait_get_category_taxonomy( $post_type );
|
||||
if ( $selected_category && $category_tax ) {
|
||||
$args['tax_query'] = [[
|
||||
'taxonomy' => $category_tax,
|
||||
'field' => 'term_id',
|
||||
'terms' => $selected_category,
|
||||
]];
|
||||
}
|
||||
$query = new WP_Query( $args );
|
||||
|
||||
// Kategorie-Filter-Formular und Pagination oben in einem flexiblen Container
|
||||
$category_filter_html = '';
|
||||
if ( $category_tax ) {
|
||||
ob_start();
|
||||
echo '<form method="get" action="" class="category-filter">';
|
||||
echo '<input type="hidden" name="page" value="ai-translate">';
|
||||
echo '<input type="hidden" name="tab" value="' . esc_attr( $post_type ) . '">';
|
||||
echo '<select name="category" onchange="this.form.submit();">';
|
||||
echo '<option value="0">Alle Kategorien</option>';
|
||||
$terms = get_terms( [ 'taxonomy' => $category_tax, 'hide_empty' => false ] );
|
||||
if ( ! is_wp_error( $terms ) ) {
|
||||
foreach ( $terms as $term ) {
|
||||
echo '<option value="' . esc_attr( $term->term_id ) . '" ' . selected( $selected_category, $term->term_id, false ) . '>' . esc_html( $term->name ) . '</option>';
|
||||
}
|
||||
}
|
||||
echo '</select>';
|
||||
echo '</form>';
|
||||
$category_filter_html = ob_get_clean();
|
||||
}
|
||||
|
||||
$pagination_html = '';
|
||||
if ( $query->max_num_pages > 1 ) {
|
||||
ob_start();
|
||||
echo '<div class="pagination" style="text-align: right;">';
|
||||
for ( $i = 1; $i <= $query->max_num_pages; $i++ ) {
|
||||
$page_url = add_query_arg( [
|
||||
'paged' => $i,
|
||||
'tab' => $post_type,
|
||||
'orderby' => $orderby,
|
||||
'order' => $order,
|
||||
'category'=> $selected_category,
|
||||
], admin_url( 'admin.php?page=ai-translate' ) );
|
||||
$class = ( $paged == $i ) ? 'button button-primary' : 'button';
|
||||
echo '<a href="' . esc_url( $page_url ) . '" class="' . esc_attr( $class ) . '">' . $i . '</a> ';
|
||||
}
|
||||
echo '</div>';
|
||||
$pagination_html = ob_get_clean();
|
||||
}
|
||||
|
||||
// Ausgabe des kombinierten Bereichs (Filter und obere Pagination)
|
||||
if ( ! empty( $category_filter_html ) || ! empty( $pagination_html ) ) {
|
||||
echo '<div class="filter-pagination" style="display: flex; justify-content: space-between; align-items: center; margin: 10px;">';
|
||||
echo '<div class="filter-left">' . $category_filter_html . '</div>';
|
||||
echo '<div class="pagination-right">' . $pagination_html . '</div>';
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
// Formular mit Tabelle
|
||||
?>
|
||||
<form id="ai-translate-form" method="post" action="">
|
||||
<!-- Versteckte Felder, um GET-Parameter beizubehalten -->
|
||||
<input type="hidden" name="page" value="ai-translate">
|
||||
<input type="hidden" name="tab" value="<?php echo esc_attr( $post_type ); ?>">
|
||||
<input type="hidden" name="category" value="<?php echo esc_attr( $selected_category ); ?>">
|
||||
<input type="hidden" name="paged" value="<?php echo esc_attr( $_GET['paged'] ?? 1 ); ?>">
|
||||
<input type="hidden" name="orderby" value="<?php echo esc_attr( $_GET['orderby'] ?? 'modified' ); ?>">
|
||||
<input type="hidden" name="order" value="<?php echo esc_attr( $_GET['order'] ?? 'desc' ); ?>">
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="checkbox-column"><input type="checkbox" id="select-all"></th>
|
||||
<th><?php echo ait_sort_link( 'Titel', 'title', $post_type ); ?></th>
|
||||
<th>Kategorie</th>
|
||||
<th><?php echo ait_sort_link( 'Last Modified', 'modified', $post_type ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
if ( $query->have_posts() ) :
|
||||
while ( $query->have_posts() ) : $query->the_post();
|
||||
$post_id = get_the_ID();
|
||||
$status = get_post_status( $post_id );
|
||||
$status_text = '';
|
||||
if ( $status === 'private' ) {
|
||||
$status_text = ' <span style="color:#a00;">(Privat)</span>';
|
||||
} elseif ( $status === 'draft' ) {
|
||||
$status_text = ' <span style="color:#a00;">(Entwurf)</span>';
|
||||
}
|
||||
?>
|
||||
<tr>
|
||||
<td class="checkbox-column">
|
||||
<input type="checkbox" name="selected_posts[]" value="<?php echo $post_id; ?>">
|
||||
</td>
|
||||
<td>
|
||||
<a href="<?php echo esc_url( get_permalink( $post_id ) ); ?>" target="_blank">
|
||||
<strong><?php echo esc_html( get_the_title() ); ?></strong>
|
||||
</a>
|
||||
<?php echo $status_text; ?>
|
||||
<br>
|
||||
<small>
|
||||
<a href="<?php echo esc_url( admin_url( 'post.php?post=' . $post_id . '&action=edit' ) ); ?>" target="_blank">
|
||||
Bearbeiten
|
||||
</a>
|
||||
</small>
|
||||
</td>
|
||||
<td><?php echo esc_html( implode( ', ', ait_get_post_categories( $post_id, $post_type ) ) ); ?></td>
|
||||
<td>
|
||||
<strong>Last Modified</strong><br>
|
||||
<?php echo esc_html( get_the_modified_date( 'Y/m/d \a\t g:i a' ) ); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
endwhile;
|
||||
else :
|
||||
?>
|
||||
<tr>
|
||||
<td colspan="4">Keine Beiträge gefunden.</td>
|
||||
</tr>
|
||||
<?php
|
||||
endif;
|
||||
wp_reset_postdata();
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>
|
||||
<input type="submit" name="save_selection" class="button button-primary" value="Zur Auswahl hinzufügen">
|
||||
</p>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
// Select-All Funktionalität
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var selectAllCheckbox = document.getElementById('select-all');
|
||||
if ( selectAllCheckbox ) {
|
||||
selectAllCheckbox.addEventListener('change', function() {
|
||||
var checkboxes = document.querySelectorAll('tbody input[type="checkbox"]');
|
||||
checkboxes.forEach(function(cb) {
|
||||
cb.checked = selectAllCheckbox.checked;
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user