// =========================================================
// WISSENSGRAPH – DEFINITION CPT
// =========================================================
add_action( 'init', function() {
register_post_type( 'bvg_definition', [
'labels' => [
'name' => 'Definitionen',
'singular_name' => 'Definition',
'add_new_item' => 'Neue Definition',
'edit_item' => 'Definition bearbeiten',
],
'public' => true,
'has_archive' => false,
'rewrite' => [
'slug' => 'definition',
'with_front' => false,
],
'supports' => [ 'title', 'editor', 'excerpt' ],
'show_in_rest' => true,
'menu_icon' => 'dashicons-networking',
'menu_position'=> 6,
] );
} );
// =========================================================
// WISSENSGRAPH – META-FELDER
// =========================================================
add_action( 'init', function() {
$auth = function() {
return current_user_can( 'edit_posts' );
};
$definition_meta = [
'_entity_uri',
'_entity_type',
'_entity_schema_type',
'_definition_url',
'_source_url',
'_sr_nummer',
'_stand_am',
'_version',
'_status',
'_airtable_record_id',
];
foreach ( $definition_meta as $key ) {
register_post_meta( 'bvg_definition', $key, [
'type' => 'string',
'single' => true,
'show_in_rest' => true,
'sanitize_callback' => 'sanitize_text_field',
'auth_callback' => $auth,
] );
}
register_post_meta( 'bvg_frage', '_bvg_mentions_json', [
'type' => 'string',
'single' => true,
'show_in_rest' => true,
'sanitize_callback' => 'wp_kses_post',
'auth_callback' => $auth,
] );
} );
// =========================================================
// WISSENSGRAPH – AIRTABLE CONFIG
// In wp-config.php setzen:
// define( 'DPK_AIRTABLE_TOKEN', 'xxx' );
// define( 'DPK_AIRTABLE_BASE_ID', 'xxx' );
// =========================================================
function dpk_airtable_is_configured() {
return defined( 'DPK_AIRTABLE_TOKEN' ) && defined( 'DPK_AIRTABLE_BASE_ID' );
}
function dpk_airtable_get_records( $table ) {
if ( ! dpk_airtable_is_configured() ) {
return [];
}
$records = [];
$offset = null;
do {
$url = 'https://api.airtable.com/v0/' .
rawurlencode( DPK_AIRTABLE_BASE_ID ) .
'/' .
rawurlencode( $table );
if ( $offset ) {
$url .= '?offset=' . rawurlencode( $offset );
}
$response = wp_remote_get( $url, [
'headers' => [
'Authorization' => 'Bearer ' . DPK_AIRTABLE_TOKEN,
],
'timeout' => 30,
] );
if ( is_wp_error( $response ) ) {
break;
}
$body = json_decode( wp_remote_retrieve_body( $response ), true );
if ( empty( $body['records'] ) || ! is_array( $body['records'] ) ) {
break;
}
$records = array_merge( $records, $body['records'] );
$offset = $body['offset'] ?? null;
} while ( $offset );
return $records;
}
// =========================================================
// WISSENSGRAPH – ENTITY UPSERT
// =========================================================
function dpk_find_definition_by_entity_uri( $entity_uri ) {
$posts = get_posts( [
'post_type' => 'bvg_definition',
'post_status' => 'any',
'meta_key' => '_entity_uri',
'meta_value' => $entity_uri,
'posts_per_page' => 1,
'fields' => 'ids',
] );
return $posts ? (int) $posts[0] : 0;
}
function dpk_upsert_definition_entity( array $record ) {
$fields = $record['fields'] ?? [];
$entity_uri = $fields['URI'] ?? '';
$name = $fields['Name'] ?? '';
if ( ! $entity_uri || ! $name ) {
return 0;
}
$existing_id = dpk_find_definition_by_entity_uri( $entity_uri );
$post_data = [
'post_type' => 'bvg_definition',
'post_status' => 'publish',
'post_title' => sanitize_text_field( $name ),
'post_excerpt' => sanitize_textarea_field( $fields['Kurzdefinition'] ?? '' ),
'post_content' => wp_kses_post( $fields['Kurzdefinition'] ?? '' ),
];
if ( $existing_id ) {
$post_data['ID'] = $existing_id;
$post_id = wp_update_post( $post_data, true );
} else {
$post_data['post_name'] = sanitize_title( $fields['Slug'] ?? $name );
$post_id = wp_insert_post( $post_data, true );
}
if ( is_wp_error( $post_id ) || ! $post_id ) {
return 0;
}
update_post_meta( $post_id, '_airtable_record_id', sanitize_text_field( $record['id'] ?? '' ) );
update_post_meta( $post_id, '_entity_uri', esc_url_raw( $entity_uri ) );
update_post_meta( $post_id, '_definition_url', esc_url_raw( $fields['Definition URL'] ?? '' ) );
update_post_meta( $post_id, '_entity_type', sanitize_text_field( $fields['Entity Type'] ?? '' ) );
update_post_meta( $post_id, '_entity_schema_type', sanitize_text_field( $fields['Schema Type'] ?? 'DefinedTerm' ) );
update_post_meta( $post_id, '_source_url', esc_url_raw( $fields['Quelle URL'] ?? '' ) );
update_post_meta( $post_id, '_sr_nummer', sanitize_text_field( $fields['SR Nummer'] ?? '' ) );
update_post_meta( $post_id, '_stand_am', sanitize_text_field( $fields['Stand am'] ?? '' ) );
update_post_meta( $post_id, '_status', sanitize_text_field( $fields['Status'] ?? '' ) );
return (int) $post_id;
}
// =========================================================
// WISSENSGRAPH – REST SYNC ENDPOINT
// Aufruf im eingeloggten Admin:
// POST /wp-json/dpk/v1/sync-entities
// =========================================================
add_action( 'rest_api_init', function() {
register_rest_route( 'dpk/v1', '/sync-entities', [
'methods' => 'POST',
'callback' => 'dpk_sync_entities_from_airtable',
'permission_callback' => function() {
return current_user_can( 'manage_options' );
},
] );
} );
function dpk_sync_entities_from_airtable() {
$records = dpk_airtable_get_records( 'Entitäten' );
$created_or_updated = [];
foreach ( $records as $record ) {
$fields = $record['fields'] ?? [];
if ( empty( $fields['Publish Definition'] ) ) {
continue;
}
$post_id = dpk_upsert_definition_entity( $record );
if ( $post_id ) {
$created_or_updated[] = [
'post_id' => $post_id,
'name' => $fields['Name'] ?? '',
'uri' => $fields['URI'] ?? '',
];
}
}
flush_rewrite_rules( false );
return rest_ensure_response( [
'success' => true,
'count' => count( $created_or_updated ),
'items' => $created_or_updated,
] );
}
// =========================================================
// WISSENSGRAPH – ENTITY REGISTRY HELPERS
// =========================================================
function dpk_get_all_definition_entities() {
$posts = get_posts( [
'post_type' => 'bvg_definition',
'post_status' => 'publish',
'posts_per_page' => -1,
] );
$entities = [];
foreach ( $posts as $post ) {
$uri = get_post_meta( $post->ID, '_entity_uri', true );
if ( ! $uri ) {
continue;
}
$entities[] = [
'post_id' => $post->ID,
'name' => get_the_title( $post->ID ),
'uri' => $uri,
'url' => get_permalink( $post->ID ),
'type' => get_post_meta( $post->ID, '_entity_schema_type', true ) ?: 'DefinedTerm',
'entity_type' => get_post_meta( $post->ID, '_entity_type', true ),
];
}
return $entities;
}
function dpk_extract_mentions_from_article_text( $post_id ) {
$text = wp_strip_all_tags(
get_the_title( $post_id ) . "\n" .
get_post_meta( $post_id, 'bvg_direktantwort', true ) . "\n" .
get_post_field( 'post_content', $post_id ) . "\n" .
get_post_meta( $post_id, 'bvg_fakten', true )
);
$entities = dpk_get_all_definition_entities();
$mentions = [];
foreach ( $entities as $entity ) {
$name = $entity['name'];
if ( ! $name ) {
continue;
}
if ( mb_stripos( $text, $name ) !== false ) {
$mentions[ $entity['uri'] ] = [
'@type' => $entity['type'],
'@id' => $entity['uri'],
'name' => $entity['name'],
'url' => $entity['url'],
];
}
}
return array_values( $mentions );
}
// =========================================================
// WISSENSGRAPH – JSON-LD FÜR DEFINITIONEN
// =========================================================
add_action( 'wp_head', function() {
if ( ! is_singular( 'bvg_definition' ) ) {
return;
}
$post_id = get_the_ID();
$entity_uri = get_post_meta( $post_id, '_entity_uri', true );
$schema_type = get_post_meta( $post_id, '_entity_schema_type', true ) ?: 'DefinedTerm';
$source_url = get_post_meta( $post_id, '_source_url', true );
$sr_nummer = get_post_meta( $post_id, '_sr_nummer', true );
$stand_am = get_post_meta( $post_id, '_stand_am', true );
$description = get_the_excerpt( $post_id );
if ( ! $entity_uri ) {
return;
}
$jsonld = [
'@context' => 'https://schema.org',
'@type' => $schema_type,
'@id' => esc_url_raw( $entity_uri ),
'name' => get_the_title( $post_id ),
'description' => wp_strip_all_tags( $description ),
'url' => get_permalink( $post_id ),
'inLanguage' => 'de-CH',
];
if ( $source_url ) {
$jsonld['sameAs'] = esc_url_raw( $source_url );
}
if ( $sr_nummer && $schema_type === 'Legislation' ) {
$jsonld['legislationIdentifier'] = 'SR ' . $sr_nummer;
$jsonld['legislationJurisdiction'] = [
'@type' => 'Country',
'name' => 'Schweiz',
];
}
if ( $stand_am ) {
$jsonld['dateModified'] = $stand_am;
}
echo "\n\n";
}, 30 );
// =========================================================
// WISSENSGRAPH – JSON-LD FÜR WISSENSARTIKEL
// ersetzt lokale #term-, #legislation-, #kennzahl-IDs
// =========================================================
add_action( 'wp_head', function() {
if ( ! is_singular( 'bvg_frage' ) ) {
return;
}
$post_id = get_the_ID();
$url = get_permalink( $post_id );
$title = get_the_title( $post_id );
$published = get_the_date( 'c', $post_id );
$modified = get_the_modified_date( 'c', $post_id );
$direktantwort = get_post_meta( $post_id, 'bvg_direktantwort', true );
$quelle = get_post_meta( $post_id, 'bvg_quelle', true );
$stand = get_post_meta( $post_id, 'bvg_stand', true );
$article_id = $url . '#article';
$page_id = $url . '#webpage';
$org_id = home_url( '/' ) . '#organization';
$website_id = home_url( '/' ) . '#website';
$mentions = dpk_extract_mentions_from_article_text( $post_id );
$about = [];
foreach ( $mentions as $mention ) {
if ( in_array( $mention['@type'], [ 'DefinedTerm', 'Legislation' ], true ) ) {
$about[] = [
'@id' => $mention['@id'],
];
}
}
$graph = [];
$graph[] = [
'@type' => 'Organization',
'@id' => $org_id,
'name' => 'Die Pensionskasse',
'url' => home_url( '/' ),
];
$graph[] = [
'@type' => 'WebSite',
'@id' => $website_id,
'name' => 'Die Pensionskasse',
'url' => home_url( '/' ),
'publisher' => [ '@id' => $org_id ],
'inLanguage' => 'de-CH',
];
$graph[] = [
'@type' => 'WebPage',
'@id' => $page_id,
'url' => $url,
'name' => $title,
'inLanguage' => 'de-CH',
'isPartOf' => [ '@id' => $website_id ],
'publisher' => [ '@id' => $org_id ],
'mainEntity' => [ '@id' => $article_id ],
'dateModified' => $modified,
];
$article = [
'@type' => 'Article',
'@id' => $article_id,
'headline' => $title,
'url' => $url,
'datePublished' => $published,
'dateModified' => $modified,
'inLanguage' => 'de-CH',
'mainEntityOfPage' => [ '@id' => $page_id ],
'publisher' => [ '@id' => $org_id ],
'mentions' => array_map( function( $entity ) {
return [ '@id' => $entity['@id'] ];
}, $mentions ),
];
if ( $about ) {
$article['about'] = $about;
}
if ( $direktantwort ) {
$article['description'] = wp_strip_all_tags( $direktantwort );
}
if ( $quelle ) {
$article['citation'] = $quelle;
$article['isBasedOn'] = $quelle;
}
if ( $stand ) {
$article['version'] = $stand;
}
$graph[] = $article;
foreach ( $mentions as $entity ) {
$graph[] = $entity;
}
$jsonld = [
'@context' => 'https://schema.org',
'@graph' => $graph,
];
echo "\n\n";
}, 30 );
https://die-pensionskasse.ch/page-sitemap.xml
2026-05-20T07:12:29+00:00
https://die-pensionskasse.ch/bvg_frage-sitemap.xml
2026-05-20T09:19:21+00:00