Changeset 3442562
- Timestamp:
- 01/19/2026 01:13:12 PM (2 months ago)
- Location:
- linktrade-monitor
- Files:
-
- 30 added
- 9 edited
-
assets/screenshot-1.png.png (added)
-
assets/screenshot-2.png.png (added)
-
assets/screenshot-3.png.png (added)
-
assets/screenshot-4.png.png (added)
-
assets/screenshot-5.png.png (added)
-
tags/1.1.2 (added)
-
tags/1.1.2/assets (added)
-
tags/1.1.2/assets/css (added)
-
tags/1.1.2/assets/css/admin.css (added)
-
tags/1.1.2/assets/images (added)
-
tags/1.1.2/assets/images/icon.png (added)
-
tags/1.1.2/assets/images/logo.png (added)
-
tags/1.1.2/assets/js (added)
-
tags/1.1.2/assets/js/admin.js (added)
-
tags/1.1.2/includes (added)
-
tags/1.1.2/includes/admin (added)
-
tags/1.1.2/includes/admin/class-admin.php (added)
-
tags/1.1.2/includes/checker (added)
-
tags/1.1.2/includes/checker/class-link-checker.php (added)
-
tags/1.1.2/includes/class-activator.php (added)
-
tags/1.1.2/includes/class-deactivator.php (added)
-
tags/1.1.2/includes/class-linktrade.php (added)
-
tags/1.1.2/includes/models (added)
-
tags/1.1.2/includes/models/class-link.php (added)
-
tags/1.1.2/languages (added)
-
tags/1.1.2/languages/linktrade-monitor-de_DE.po (added)
-
tags/1.1.2/languages/translations-de.php (added)
-
tags/1.1.2/linktrade-monitor.php (added)
-
tags/1.1.2/readme.txt (added)
-
tags/1.1.2/uninstall.php (added)
-
trunk/assets/css/admin.css (modified) (3 diffs)
-
trunk/assets/js/admin.js (modified) (3 diffs)
-
trunk/includes/admin/class-admin.php (modified) (16 diffs)
-
trunk/includes/class-activator.php (modified) (5 diffs)
-
trunk/includes/class-linktrade.php (modified) (2 diffs)
-
trunk/languages/linktrade-monitor-de_DE.po (modified) (4 diffs)
-
trunk/languages/translations-de.php (modified) (5 diffs)
-
trunk/linktrade-monitor.php (modified) (4 diffs)
-
trunk/readme.txt (modified) (7 diffs)
Legend:
- Unmodified
- Added
- Removed
-
linktrade-monitor/trunk/assets/css/admin.css
r3441905 r3442562 1 1 /** 2 * Linktrade Monitor - Admin Styles v1. 32 * Linktrade Monitor - Admin Styles v1.4 3 3 * Design: Clean Minimal + Modal 4 4 */ … … 722 722 } 723 723 724 /* DR Comparison */ 725 .dr-comparison { 726 white-space: nowrap; 727 } 728 729 .dr-vs { 730 font-size: 0.65rem; 731 color: #9ca3af; 732 margin: 0 3px; 733 } 734 735 .dr-badge.dr-mine { 736 background: #fef3c7; 737 color: #d97706; 738 } 739 740 .dr-diff { 741 font-size: 0.65rem; 742 font-weight: 600; 743 padding: 2px 5px; 744 border-radius: 3px; 745 margin-left: 6px; 746 } 747 748 .dr-diff.dr-positive { 749 background: #d1fae5; 750 color: #047857; 751 } 752 753 .dr-diff.dr-negative { 754 background: #fee2e2; 755 color: #dc2626; 756 } 757 758 .dr-diff.dr-neutral { 759 background: #f3f4f6; 760 color: #6b7280; 761 } 762 763 /* Form Grid (side by side fields) */ 764 .form-row-grid { 765 display: grid; 766 grid-template-columns: 1fr 1fr; 767 gap: 20px; 768 margin-bottom: 12px; 769 } 770 771 .form-row-grid .form-row { 772 margin-bottom: 0; 773 } 774 775 .form-row-grid .form-row label { 776 display: block; 777 font-weight: 500; 778 margin-bottom: 6px; 779 color: #374151; 780 font-size: 0.9rem; 781 } 782 783 .form-row-grid .form-row input { 784 width: 100%; 785 padding: 10px 14px; 786 border: 1px solid #d1d5db; 787 border-radius: 8px; 788 font-size: 0.95rem; 789 } 790 791 .form-row-grid + .description { 792 margin-top: 4px; 793 margin-bottom: 16px; 794 font-size: 0.85rem; 795 color: #6b7280; 796 } 797 798 .linktrade-form .form-row .description { 799 margin-top: 6px; 800 font-size: 0.85rem; 801 color: #6b7280; 802 } 803 724 804 /* Quality Badge */ 725 805 .quality-badge { … … 1448 1528 } 1449 1529 1530 /* Expiration Badges */ 1531 .date-start { 1532 color: #6b7280; 1533 font-size: 0.85rem; 1534 } 1535 1536 .expiry-badge { 1537 display: inline-block; 1538 padding: 2px 8px; 1539 border-radius: 4px; 1540 font-size: 0.75rem; 1541 font-weight: 600; 1542 } 1543 1544 .expiry-badge.expired { 1545 background: #fee2e2; 1546 color: #dc2626; 1547 } 1548 1549 .expiry-badge.expiring { 1550 background: #fef3c7; 1551 color: #d97706; 1552 } 1553 1450 1554 /* Notice */ 1451 1555 .linktrade-notice { -
linktrade-monitor/trunk/assets/js/admin.js
r3441905 r3442562 3 3 * 4 4 * @package Linktrade_Monitor 5 * @version 1.1. 05 * @version 1.1.2 6 6 */ 7 7 … … 214 214 <input type="url" id="edit_backlink_target" name="backlink_target" value="${this.escapeHtml(link.backlink_target || '')}"> 215 215 </div> 216 <div class="form-row"> 217 <label for="edit_backlink_anchor">Anchor Text</label> 218 <input type="text" id="edit_backlink_anchor" name="backlink_anchor" value="${this.escapeHtml(link.backlink_anchor || '')}"> 219 </div> 216 220 </div> 217 221 … … 219 223 <h4>Additional Info</h4> 220 224 <div class="form-row"> 221 <label for="edit_domain_rating">Domain Rating (DR)</label> 222 <input type="number" id="edit_domain_rating" name="domain_rating" value="${link.domain_rating || ''}" min="0" max="100"> 225 <label for="edit_start_date">Start Date</label> 226 <input type="date" id="edit_start_date" name="start_date" value="${link.start_date || ''}"> 227 </div> 228 <div class="form-row"> 229 <label for="edit_end_date">Expiration Date</label> 230 <input type="date" id="edit_end_date" name="end_date" value="${link.end_date || ''}"> 231 </div> 232 <div class="form-row-grid"> 233 <div class="form-row"> 234 <label for="edit_domain_rating">Partner DR</label> 235 <input type="number" id="edit_domain_rating" name="domain_rating" value="${link.domain_rating || ''}" min="0" max="100"> 236 </div> 237 <div class="form-row"> 238 <label for="edit_my_domain_rating">My DR</label> 239 <input type="number" id="edit_my_domain_rating" name="my_domain_rating" value="${link.my_domain_rating || ''}" min="0" max="100"> 240 </div> 223 241 </div> 224 242 <div class="form-row"> -
linktrade-monitor/trunk/includes/admin/class-admin.php
r3441905 r3442562 195 195 ), 196 196 'add' => array( 197 'label' => __( ' +New', 'linktrade-monitor' ),197 'label' => __( 'New', 'linktrade-monitor' ), 198 198 'icon' => 'dashicons-plus', 199 199 ), … … 398 398 <th><?php esc_html_e( 'Category', 'linktrade-monitor' ); ?></th> 399 399 <th><?php esc_html_e( 'Status', 'linktrade-monitor' ); ?></th> 400 <th><?php esc_html_e( 'Start / Expiration', 'linktrade-monitor' ); ?></th> 400 401 <th><?php esc_html_e( 'DR', 'linktrade-monitor' ); ?></th> 401 402 <th><?php esc_html_e( 'Last Check', 'linktrade-monitor' ); ?></th> … … 406 407 <?php if ( empty( $links ) ) : ?> 407 408 <tr> 408 <td colspan=" 6" class="linktrade-empty">409 <td colspan="7" class="linktrade-empty"> 409 410 <?php esc_html_e( 'No links found. Add your first link!', 'linktrade-monitor' ); ?> 410 411 </td> … … 424 425 <td> 425 426 <?php echo wp_kses_post( $this->render_status_badge( $link ) ); ?> 427 </td> 428 <td> 429 <?php echo wp_kses_post( $this->render_date_info( $link ) ); ?> 426 430 </td> 427 431 <td> … … 488 492 <th><?php esc_html_e( 'Their Link to You', 'linktrade-monitor' ); ?></th> 489 493 <th><?php esc_html_e( 'Your Link to Them', 'linktrade-monitor' ); ?></th> 494 <th><?php esc_html_e( 'DR', 'linktrade-monitor' ); ?></th> 490 495 <th><?php esc_html_e( 'Fairness', 'linktrade-monitor' ); ?></th> 491 496 </tr> … … 494 499 <?php if ( empty( $links ) ) : ?> 495 500 <tr> 496 <td colspan=" 4" class="linktrade-empty"><?php esc_html_e( 'No link exchange partners found.', 'linktrade-monitor' ); ?></td>501 <td colspan="5" class="linktrade-empty"><?php esc_html_e( 'No link exchange partners found.', 'linktrade-monitor' ); ?></td> 497 502 </tr> 498 503 <?php else : ?> … … 505 510 $fairness_class = 'warning'; 506 511 } 512 // DR comparison (per link). 513 $partner_dr = (int) $link->domain_rating; 514 $my_dr = isset( $link->my_domain_rating ) ? (int) $link->my_domain_rating : 0; 515 $dr_diff = $partner_dr - $my_dr; 507 516 ?> 508 517 <tr data-id="<?php echo esc_attr( $link->id ); ?>" class="fairness-row fairness-<?php echo esc_attr( $fairness_class ); ?>"> 509 518 <td> 510 519 <strong><?php echo esc_html( $link->partner_name ); ?></strong> 511 <?php if ( $link->domain_rating ) : ?>512 <span class="dr-badge">DR <?php echo esc_html( $link->domain_rating ); ?></span>513 <?php endif; ?>514 520 </td> 515 521 <td> … … 523 529 <?php else : ?> 524 530 <span class="status unchecked"><?php esc_html_e( 'Not set', 'linktrade-monitor' ); ?></span> 531 <?php endif; ?> 532 </td> 533 <td class="dr-comparison"> 534 <?php if ( $partner_dr > 0 && $my_dr > 0 ) : ?> 535 <span class="dr-badge"><?php echo esc_html( $partner_dr ); ?></span> 536 <span class="dr-vs">vs</span> 537 <span class="dr-badge dr-mine"><?php echo esc_html( $my_dr ); ?></span> 538 <?php if ( $dr_diff > 0 ) : ?> 539 <span class="dr-diff dr-positive">+<?php echo esc_html( $dr_diff ); ?></span> 540 <?php elseif ( $dr_diff < 0 ) : ?> 541 <span class="dr-diff dr-negative"><?php echo esc_html( $dr_diff ); ?></span> 542 <?php else : ?> 543 <span class="dr-diff dr-neutral">=</span> 544 <?php endif; ?> 545 <?php elseif ( $partner_dr > 0 ) : ?> 546 <span class="dr-badge"><?php echo esc_html( $partner_dr ); ?></span> 547 <span class="dr-vs">vs</span> 548 <span class="dr-badge dr-mine">?</span> 549 <?php elseif ( $my_dr > 0 ) : ?> 550 <span class="dr-badge">?</span> 551 <span class="dr-vs">vs</span> 552 <span class="dr-badge dr-mine"><?php echo esc_html( $my_dr ); ?></span> 553 <?php else : ?> 554 - 525 555 <?php endif; ?> 526 556 </td> … … 552 582 <form id="linktrade-add-form" class="linktrade-form"> 553 583 <div class="form-section"> 584 <h4><?php esc_html_e( 'Start Date', 'linktrade-monitor' ); ?></h4> 585 <div class="form-row"> 586 <label for="start_date"><?php esc_html_e( 'When was the link placed?', 'linktrade-monitor' ); ?></label> 587 <input type="date" id="start_date" name="start_date" value="<?php echo esc_attr( gmdate( 'Y-m-d' ) ); ?>"> 588 </div> 589 </div> 590 591 <div class="form-section"> 554 592 <h4><?php esc_html_e( 'Partner Information', 'linktrade-monitor' ); ?></h4> 555 593 … … 605 643 <input type="url" id="backlink_target" name="backlink_target" placeholder="https://partner-site.com/their-page"> 606 644 </div> 645 646 <div class="form-row"> 647 <label for="backlink_anchor"><?php esc_html_e( 'Anchor Text (your link)', 'linktrade-monitor' ); ?></label> 648 <input type="text" id="backlink_anchor" name="backlink_anchor" placeholder="<?php esc_attr_e( 'e.g. Partner Name', 'linktrade-monitor' ); ?>"> 649 </div> 607 650 </div> 608 651 … … 611 654 612 655 <div class="form-row"> 613 <label for="domain_rating"><?php esc_html_e( 'Domain Rating (DR)', 'linktrade-monitor' ); ?></label> 614 <input type="number" id="domain_rating" name="domain_rating" min="0" max="100"> 615 </div> 656 <label for="end_date"><?php esc_html_e( 'Expiration Date', 'linktrade-monitor' ); ?></label> 657 <input type="date" id="end_date" name="end_date"> 658 <p class="description"><?php esc_html_e( 'Only for time-limited agreements. Leave empty for permanent links.', 'linktrade-monitor' ); ?></p> 659 </div> 660 661 <div class="form-row-grid"> 662 <div class="form-row"> 663 <label for="domain_rating"><?php esc_html_e( 'Partner DR', 'linktrade-monitor' ); ?></label> 664 <input type="number" id="domain_rating" name="domain_rating" min="0" max="100" placeholder="0-100"> 665 </div> 666 <div class="form-row"> 667 <label for="my_domain_rating"><?php esc_html_e( 'My DR', 'linktrade-monitor' ); ?></label> 668 <input type="number" id="my_domain_rating" name="my_domain_rating" min="0" max="100" placeholder="0-100"> 669 </div> 670 </div> 671 <p class="description"><?php esc_html_e( 'Domain Rating for fairness comparison. Get DR from Ahrefs, Moz, or similar tools.', 'linktrade-monitor' ); ?></p> 616 672 617 673 <div class="form-row"> … … 646 702 $reminder_days = isset( $_POST['reminder_days'] ) ? absint( $_POST['reminder_days'] ) : 14; 647 703 $plugin_language = isset( $_POST['plugin_language'] ) ? sanitize_key( wp_unslash( $_POST['plugin_language'] ) ) : 'en'; 648 $credit_link_type = isset( $_POST['credit_link_type'] ) ? sanitize_key( wp_unslash( $_POST['credit_link_type'] ) ) : 'none';649 704 650 705 update_option( 'linktrade_notification_email', $notification_email ); … … 809 864 810 865 /** 866 * Helper: Render date info (start date + expiration) 867 * 868 * @param object $link Link object. 869 * @return string HTML date info. 870 */ 871 private function render_date_info( $link ) { 872 $output = ''; 873 874 // Show start date. 875 if ( ! empty( $link->start_date ) && '0000-00-00' !== $link->start_date ) { 876 $start_formatted = wp_date( get_option( 'date_format' ), strtotime( $link->start_date ) ); 877 $output .= '<span class="date-start">' . esc_html( $start_formatted ) . '</span>'; 878 } else { 879 $output .= '<span class="date-start">-</span>'; 880 } 881 882 // Show expiration status if end_date is set. 883 if ( ! empty( $link->end_date ) && '0000-00-00' !== $link->end_date ) { 884 $end_timestamp = strtotime( $link->end_date ); 885 $now = current_time( 'timestamp' ); 886 $days_until_expiry = (int) ceil( ( $end_timestamp - $now ) / DAY_IN_SECONDS ); 887 888 if ( $days_until_expiry < 0 ) { 889 // Already expired. 890 $output .= '<br><span class="expiry-badge expired">' . esc_html__( 'Expired', 'linktrade-monitor' ) . '</span>'; 891 } elseif ( $days_until_expiry <= 30 ) { 892 // Expiring soon (within 30 days). 893 $output .= '<br><span class="expiry-badge expiring">'; 894 /* translators: %d: number of days until expiration */ 895 $output .= sprintf( esc_html__( '%d days left', 'linktrade-monitor' ), $days_until_expiry ); 896 $output .= '</span>'; 897 } else { 898 // Not expiring soon - show end date. 899 $end_formatted = wp_date( get_option( 'date_format' ), $end_timestamp ); 900 $output .= '<br><small>' . esc_html__( 'until', 'linktrade-monitor' ) . ' ' . esc_html( $end_formatted ) . '</small>'; 901 } 902 } 903 904 return $output; 905 } 906 907 /** 811 908 * Helper: Render backlink status badge 812 909 * … … 863 960 'backlink_target' => isset( $_POST['backlink_target'] ) ? esc_url_raw( wp_unslash( $_POST['backlink_target'] ) ) : '', 864 961 'backlink_anchor' => isset( $_POST['backlink_anchor'] ) ? sanitize_text_field( wp_unslash( $_POST['backlink_anchor'] ) ) : '', 865 'domain_rating' => isset( $_POST['domain_rating'] ) ? absint( $_POST['domain_rating'] ) : 0, 866 'notes' => isset( $_POST['notes'] ) ? sanitize_textarea_field( wp_unslash( $_POST['notes'] ) ) : '', 962 'domain_rating' => isset( $_POST['domain_rating'] ) ? absint( $_POST['domain_rating'] ) : 0, 963 'my_domain_rating' => isset( $_POST['my_domain_rating'] ) ? absint( $_POST['my_domain_rating'] ) : 0, 964 'notes' => isset( $_POST['notes'] ) ? sanitize_textarea_field( wp_unslash( $_POST['notes'] ) ) : '', 965 'start_date' => isset( $_POST['start_date'] ) && ! empty( $_POST['start_date'] ) ? sanitize_text_field( wp_unslash( $_POST['start_date'] ) ) : null, 966 'end_date' => isset( $_POST['end_date'] ) && ! empty( $_POST['end_date'] ) ? sanitize_text_field( wp_unslash( $_POST['end_date'] ) ) : null, 867 967 ); 868 968 … … 892 992 $message .= ' ' . __( 'Link checked.', 'linktrade-monitor' ); 893 993 } 994 995 // For exchanges, also check the backlink (your link to partner). 996 if ( 'exchange' === $data['category'] && ! empty( $data['backlink_url'] ) && ! empty( $data['backlink_target'] ) ) { 997 $backlink_result = $this->check_backlink( $id, $data['backlink_url'], $data['backlink_target'] ); 998 if ( $backlink_result ) { 999 $message .= ' ' . __( 'Backlink checked.', 'linktrade-monitor' ); 1000 } 1001 } 1002 } 1003 1004 // Recalculate fairness for exchange links when DR values change. 1005 if ( 'exchange' === $data['category'] ) { 1006 $this->recalculate_fairness( $id, $data['domain_rating'], $data['my_domain_rating'] ); 894 1007 } 895 1008 … … 946 1059 947 1060 /** 1061 * Check the backlink (your link to partner) immediately. 1062 * 1063 * @param int $link_id The link ID. 1064 * @param string $page_url Your page URL where you placed the link. 1065 * @param string $target_url Partner's URL you link to. 1066 * @return array|null Check result or null on failure. 1067 */ 1068 private function check_backlink( $link_id, $page_url, $target_url ) { 1069 require_once LINKTRADE_PLUGIN_DIR . 'includes/checker/class-link-checker.php'; 1070 1071 $checker = new Linktrade_Link_Checker(); 1072 $result = $checker->check( $page_url, $target_url ); 1073 1074 if ( ! $result ) { 1075 return null; 1076 } 1077 1078 // Update backlink fields in database. 1079 global $wpdb; 1080 $table_name = $wpdb->prefix . 'linktrade_links'; 1081 1082 $update_data = array( 1083 'backlink_status' => $result['status'], 1084 'backlink_last_check' => current_time( 'mysql' ), 1085 'backlink_http_code' => $result['http_code'], 1086 'backlink_is_nofollow' => $result['is_nofollow'] ? 1 : 0, 1087 ); 1088 1089 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Update operation on custom table. 1090 $wpdb->update( $table_name, $update_data, array( 'id' => $link_id ) ); 1091 1092 return $result; 1093 } 1094 1095 /** 1096 * Recalculate fairness score for a link based on current status and DR values. 1097 * 1098 * @param int $link_id The link ID. 1099 * @param int $partner_dr Partner's Domain Rating. 1100 * @param int $my_dr My Domain Rating. 1101 */ 1102 private function recalculate_fairness( $link_id, $partner_dr, $my_dr ) { 1103 global $wpdb; 1104 $table_name = $wpdb->prefix . 'linktrade_links'; 1105 1106 // Get current link status. 1107 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Query on custom table. 1108 $link = $wpdb->get_row( 1109 $wpdb->prepare( 1110 'SELECT status, is_nofollow, backlink_status, backlink_is_nofollow FROM `' . esc_sql( $table_name ) . '` WHERE id = %d', 1111 $link_id 1112 ) 1113 ); 1114 1115 if ( ! $link ) { 1116 return; 1117 } 1118 1119 // Calculate fairness with status and DR values. 1120 $fairness = $this->calculate_fairness_score( 1121 $link->status, 1122 $link->backlink_status, 1123 (bool) $link->is_nofollow, 1124 (bool) $link->backlink_is_nofollow, 1125 (int) $partner_dr, 1126 (int) $my_dr 1127 ); 1128 1129 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Update operation on custom table. 1130 $wpdb->update( 1131 $table_name, 1132 array( 'fairness_score' => $fairness ), 1133 array( 'id' => $link_id ), 1134 array( '%d' ), 1135 array( '%d' ) 1136 ); 1137 } 1138 1139 /** 1140 * Calculate fairness score. 1141 * 1142 * @param string $my_status My link status (their link to me). 1143 * @param string $their_status Their link status (my link to them). 1144 * @param bool $my_nofollow My incoming link nofollow. 1145 * @param bool $their_nofollow My outgoing link nofollow. 1146 * @param int $partner_dr Partner's Domain Rating. 1147 * @param int $my_dr My Domain Rating. 1148 * @return int Fairness score (0-100). 1149 */ 1150 private function calculate_fairness_score( $my_status, $their_status, $my_nofollow, $their_nofollow, $partner_dr = 0, $my_dr = 0 ) { 1151 // Base fairness from link status. 1152 if ( 'online' === $my_status && 'offline' === $their_status ) { 1153 return 0; // Partner removed their link but I still link to them. 1154 } 1155 if ( 'offline' === $my_status && 'offline' === $their_status ) { 1156 return 50; // Both links offline. 1157 } 1158 1159 $base_score = 100; 1160 1161 // Nofollow penalty. 1162 if ( ! $my_nofollow && $their_nofollow ) { 1163 $base_score = 60; // I give dofollow, partner gives nofollow. 1164 } 1165 1166 // DR comparison adjustment (only if both values are set). 1167 if ( $partner_dr > 0 && $my_dr > 0 ) { 1168 $dr_diff = $my_dr - $partner_dr; 1169 1170 // If my DR is higher, I'm giving more value than I receive. 1171 if ( $dr_diff > 0 ) { 1172 // Reduce fairness: -2 points per DR difference, max -40. 1173 $dr_penalty = min( 40, $dr_diff * 2 ); 1174 $base_score = max( 0, $base_score - $dr_penalty ); 1175 } 1176 } 1177 1178 return $base_score; 1179 } 1180 1181 /** 948 1182 * AJAX: Delete link 949 1183 */ -
linktrade-monitor/trunk/includes/class-activator.php
r3441905 r3442562 22 22 // Check if this is a fresh install or upgrade 23 23 $current_version = get_option( 'linktrade_version', '0.0.0' ); 24 24 25 25 if ( version_compare( $current_version, LINKTRADE_VERSION, '<' ) ) { 26 26 self::create_tables(); 27 } 28 27 self::run_migrations( $current_version ); 28 } 29 29 30 self::set_default_options(); 30 31 self::schedule_crons(); … … 93 94 /* Partner metrics */ 94 95 domain_rating TINYINT UNSIGNED DEFAULT 0, 96 my_domain_rating TINYINT UNSIGNED DEFAULT 0, 95 97 domain_authority TINYINT UNSIGNED DEFAULT 0, 96 98 monthly_traffic INT UNSIGNED DEFAULT 0, … … 190 192 private static function set_default_options() { 191 193 $defaults = array( 192 'linktrade_check_frequency' => ' biweekly', // every 2 weeks194 'linktrade_check_frequency' => 'monthly', // once a month 193 195 'linktrade_email_notifications' => true, 194 196 'linktrade_notification_email' => get_option( 'admin_email' ), … … 209 211 210 212 /** 211 * Schedule cron jobs - Biweekly check (every 2 weeks)213 * Schedule cron jobs - Monthly check (once a month) 212 214 */ 213 215 private static function schedule_crons() { 214 // Biweekly link check (every 2 weeks)216 // Monthly link check (once a month) 215 217 if ( ! wp_next_scheduled( 'linktrade_check_links' ) ) { 216 wp_schedule_event( time(), ' biweekly', 'linktrade_check_links' );218 wp_schedule_event( time(), 'monthly', 'linktrade_check_links' ); 217 219 } 218 220 … … 222 224 } 223 225 } 226 227 /** 228 * Run database migrations for upgrades 229 * 230 * @param string $from_version Previous version. 231 */ 232 private static function run_migrations( $from_version ) { 233 global $wpdb; 234 $table_name = $wpdb->prefix . 'linktrade_links'; 235 236 // Migration for v1.1.1: Add my_domain_rating column 237 if ( version_compare( $from_version, '1.1.1', '<' ) ) { 238 // Check if column exists 239 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- One-time migration check. 240 $column_exists = $wpdb->get_results( 241 $wpdb->prepare( 242 "SHOW COLUMNS FROM `{$table_name}` LIKE %s", 243 'my_domain_rating' 244 ) 245 ); 246 247 if ( empty( $column_exists ) ) { 248 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange -- One-time migration. 249 $wpdb->query( "ALTER TABLE `{$table_name}` ADD COLUMN `my_domain_rating` TINYINT UNSIGNED DEFAULT 0 AFTER `domain_rating`" ); 250 } 251 } 252 } 224 253 } -
linktrade-monitor/trunk/includes/class-linktrade.php
r3441905 r3442562 115 115 $backlink_result['status'], 116 116 $result['is_nofollow'], 117 $backlink_result['is_nofollow'] 117 $backlink_result['is_nofollow'], 118 isset( $link->domain_rating ) ? (int) $link->domain_rating : 0, 119 isset( $link->my_domain_rating ) ? (int) $link->my_domain_rating : 0 118 120 ); 119 121 } … … 191 193 * Calculate fairness score 192 194 * 193 * @param string $my_status My link status. 194 * @param string $their_status Their link status. 195 * @param bool $my_nofollow My link nofollow. 196 * @param bool $their_nofollow Their link nofollow. 197 * @return int Fairness score. 198 */ 199 private function calculate_fairness( $my_status, $their_status, $my_nofollow, $their_nofollow ) { 195 * @param string $my_status My link status (their link to me). 196 * @param string $their_status Their link status (my link to them). 197 * @param bool $my_nofollow My incoming link nofollow. 198 * @param bool $their_nofollow My outgoing link nofollow. 199 * @param int $partner_dr Partner's Domain Rating. 200 * @param int $my_dr My Domain Rating. 201 * @return int Fairness score (0-100). 202 */ 203 private function calculate_fairness( $my_status, $their_status, $my_nofollow, $their_nofollow, $partner_dr = 0, $my_dr = 0 ) { 204 // Base fairness from link status. 200 205 if ( 'online' === $my_status && 'offline' === $their_status ) { 201 return 0; 206 return 0; // Partner removed their link but I still link to them. 202 207 } 203 208 if ( 'offline' === $my_status && 'offline' === $their_status ) { 204 return 50; 205 } 209 return 50; // Both links offline. 210 } 211 212 $base_score = 100; 213 214 // Nofollow penalty. 206 215 if ( ! $my_nofollow && $their_nofollow ) { 207 return 60; 208 } 209 return 100; 216 $base_score = 60; // I give dofollow, partner gives nofollow. 217 } 218 219 // DR comparison adjustment (only if both values are set). 220 if ( $partner_dr > 0 && $my_dr > 0 ) { 221 $dr_diff = $my_dr - $partner_dr; 222 223 // If my DR is higher, I'm giving more value than I receive. 224 if ( $dr_diff > 0 ) { 225 // Reduce fairness: -2 points per DR difference, max -40. 226 $dr_penalty = min( 40, $dr_diff * 2 ); 227 $base_score = max( 0, $base_score - $dr_penalty ); 228 } 229 } 230 231 return $base_score; 210 232 } 211 233 } -
linktrade-monitor/trunk/languages/linktrade-monitor-de_DE.po
r3441905 r3442562 6 6 msgid "" 7 7 msgstr "" 8 "Project-Id-Version: Linktrade Monitor 1. 0.5\n"8 "Project-Id-Version: Linktrade Monitor 1.1.1\n" 9 9 "Report-Msgid-Bugs-To: https://frank-stemmler.de\n" 10 10 "POT-Creation-Date: 2025-01-11 12:00+0000\n" … … 17 17 "Content-Transfer-Encoding: 8bit\n" 18 18 "Plural-Forms: nplurals=2; plural=(n != 1);\n" 19 "X-Generator: Claude Code\n"19 "X-Generator: Poedit 3.4\n" 20 20 21 21 # Plugin action links … … 57 57 msgstr "Link geprüft." 58 58 59 msgid "Backlink checked." 60 msgstr "Backlink geprüft." 61 59 62 # Tabs 60 63 msgid "Dashboard" … … 67 70 msgstr "Fairness" 68 71 69 msgid " +New"70 msgstr " +Neu"72 msgid "New" 73 msgstr "Neu" 71 74 72 75 # Dashboard -
linktrade-monitor/trunk/languages/translations-de.php
r3441905 r3442562 30 30 31 31 // Check frequency 32 ' Every 2 Weeks' => 'Alle 2 Wochen',32 'Once a Month' => 'Einmal monatlich', 33 33 'Link checked.' => 'Link geprüft.', 34 'Backlink checked.' => 'Backlink geprüft.', 34 35 35 36 // Tabs … … 37 38 'All Links' => 'Alle Links', 38 39 'Fairness' => 'Fairness', 39 ' + New' => '+Neu',40 'New' => 'Neu', 40 41 41 42 // Dashboard … … 65 66 'Category' => 'Kategorie', 66 67 'Status' => 'Status', 68 'Start / Expiration' => 'Start / Ablauf', 67 69 'DR' => 'DR', 68 70 'Last Check' => 'Letzte Prüfung', … … 89 91 'Not set' => 'Nicht eingetragen', 90 92 93 // Timing fields 94 'Start Date' => 'Startdatum', 95 'When was the link placed?' => 'Wann wurde der Link gesetzt?', 96 'Expiration Date' => 'Ablaufdatum', 97 'Only for time-limited agreements. Leave empty for permanent links.' => 'Nur für befristete Vereinbarungen. Bei permanenten Links leer lassen.', 98 'Expired' => 'Abgelaufen', 99 '%d days left' => 'Noch %d Tage', 100 'until' => 'bis', 101 91 102 // Add form 92 103 'Add New Link' => 'Neuen Link hinzufügen', … … 101 112 'Your page with link to partner' => 'Deine Seite mit Link zum Partner', 102 113 'Partner URL you link to' => 'Partner-URL die du verlinkst', 114 'Anchor Text (your link)' => 'Ankertext (dein Link)', 115 'e.g. Partner Name' => 'z.B. Partner-Name', 103 116 'Additional Info (optional)' => 'Zusätzliche Infos (optional)', 104 'Domain Rating (DR)' => 'Domain Rating (DR)', 117 'Partner DR' => 'Partner DR', 118 'My DR' => 'Mein DR', 119 'Domain Rating for fairness comparison. Get DR from Ahrefs, Moz, or similar tools.' => 'Domain Rating für Fairness-Vergleich. DR von Ahrefs, Moz oder ähnlichen Tools.', 105 120 'Notes' => 'Notizen', 106 121 'Save Link' => 'Link speichern', -
linktrade-monitor/trunk/linktrade-monitor.php
r3441905 r3442562 4 4 * Plugin URI: https://wordpress.org/plugins/linktrade-monitor/ 5 5 * Description: Backlink management and monitoring for WordPress. Track link exchanges, paid links, and free backlinks. 6 * Version: 1. 0.56 * Version: 1.1.2 7 7 * Author: 3task 8 8 * Author URI: https://www.3task.de … … 22 22 23 23 // Plugin constants. 24 define( 'LINKTRADE_VERSION', '1. 0.5' );24 define( 'LINKTRADE_VERSION', '1.1.2' ); 25 25 define( 'LINKTRADE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); 26 26 define( 'LINKTRADE_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); … … 45 45 } 46 46 register_deactivation_hook( __FILE__, 'linktrade_deactivate' ); 47 48 /** 49 * Check for plugin updates and run migrations if needed. 50 */ 51 function linktrade_check_version() { 52 $current_version = get_option( 'linktrade_version', '0.0.0' ); 53 54 if ( version_compare( $current_version, LINKTRADE_VERSION, '<' ) ) { 55 require_once LINKTRADE_PLUGIN_DIR . 'includes/class-activator.php'; 56 Linktrade_Activator::activate(); 57 } 58 } 59 add_action( 'admin_init', 'linktrade_check_version' ); 47 60 48 61 /** … … 141 154 */ 142 155 function linktrade_add_cron_interval( $schedules ) { 143 $schedules[' biweekly'] = array(144 'interval' => 14* DAY_IN_SECONDS,145 'display' => esc_html__( ' Every 2 Weeks', 'linktrade-monitor' ),156 $schedules['monthly'] = array( 157 'interval' => 30 * DAY_IN_SECONDS, 158 'display' => esc_html__( 'Once a Month', 'linktrade-monitor' ), 146 159 ); 147 160 return $schedules; -
linktrade-monitor/trunk/readme.txt
r3441910 r3442562 5 5 Tested up to: 6.9 6 6 Requires PHP: 7.4 7 Stable tag: 1. 0.57 Stable tag: 1.1.2 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 31 31 * **Three Link Categories** - Track exchanges, paid links, and free backlinks separately 32 32 * **Instant Check on Add** - Every new link is verified immediately 33 * **Automatic Checking** - Biweekly automated link verification (every 2 weeks) 33 * **Automatic Checking** - Monthly automated link verification (once a month) 34 * **Exchange Duration Tracking** - Track start dates and expiration for time-limited exchanges 34 35 * **HTTP Status Monitoring** - Track 200, 301, 404, and other status codes 35 36 * **nofollow/noindex Detection** - Get warned about link attribute changes … … 59 60 | Partner Categories | **Yes** | No | 60 61 61 = Need More Power? =62 63 [LinkTrade Monitor Pro](https://www.3task.de/linktrade-monitor-pro/) offers advanced automation features:64 65 * **Daily automated checks** instead of biweekly66 * **Bulk import/export** for large link portfolios67 * **Advanced email alerts** with detailed reports68 * **Priority support** from the development team69 70 [Learn more about Pro](https://www.3task.de/linktrade-monitor-pro/)71 72 62 == Installation == 73 63 … … 81 71 = How often are links checked? = 82 72 83 Links are checked instantly when you add them, plus automatic checks every 2 weeks.73 Links are checked instantly when you add them, plus automatic checks once a month. 84 74 85 75 = What does the Fairness Score mean? = … … 110 100 Yes! Linktrade Monitor works alongside Yoast SEO, Rank Math, AIOSEO, and any other SEO plugin. 111 101 112 = Is there a Pro version? =113 114 Yes! [LinkTrade Monitor Pro](https://www.3task.de/linktrade-monitor-pro/) adds automation features like daily checks, bulk operations, and advanced alerts. The free version is fully functional for manual link management.115 116 102 == Screenshots == 117 103 … … 122 108 123 109 == Changelog == 110 111 = 1.1.2 = 112 * Fixed: Fairness Score now includes DR comparison in calculation 113 * Improved: Fairness is recalculated when DR values are changed 114 * New: Fairness reflects value imbalance when your DR is higher than partner's DR 115 116 = 1.1.1 = 117 * New: Start date field moved to top of form for better workflow 118 * New: "My DR" field per link for accurate DR comparison across multiple projects 119 * New: DR comparison column in Fairness tab shows Partner DR vs My DR with difference indicator 120 * New: Backlink anchor text field for reciprocal links 121 * Improved: Form layout with side-by-side DR fields (Partner DR | My DR) 122 * Improved: Visual DR difference indicators (+green for benefit, -red for partner benefit) 123 124 = 1.1.0 = 125 * New: Exchange start date tracking - know when each link exchange began 126 * New: Expiration date support for time-limited exchanges (e.g. 1 year agreements) 127 * New: Visual expiration indicators in link overview (expired, expiring soon) 128 * Improved: Link overview now shows start date and expiration status 124 129 125 130 = 1.0.0 = … … 136 141 == Upgrade Notice == 137 142 143 = 1.1.2 = 144 Fairness Score now properly reflects DR imbalance. Update recommended for accurate fairness tracking. 145 146 = 1.1.1 = 147 New: Track your own DR per link for accurate fairness comparison across multiple projects. Improved form workflow. 148 149 = 1.1.0 = 150 New: Track exchange start dates and expiration for time-limited link agreements. 151 138 152 = 1.0.0 = 139 153 First stable release. Start tracking your backlinks and link exchanges today!
Note: See TracChangeset
for help on using the changeset viewer.